So I'm trying to build a sudoku app with React and I've separated everything into 4 components. It basically goes like this App -> Board -> Row -> Cell where the cell is the smallest unit. Now every cell is a <div> tag for which I used tabIndex="0" to navigate with the keys and enter values in the cell.
I render all my cells by using .map() to go through an array of data. Initially, I didn't specify a key property for every element of my array and everything was working fine. Every cell I had was working perfectly whenever I pressed a key. However, as soon as I specify a key property of the cell it seems like my handler function for onKeyDown isn't working at all. I'm completely baffled, if anyone has any insights I would appreciate it.
Just to specify, I'm using uuid() to generate a unique key but every other method I've tried doesn't work as well. It seems to be some relationship between the key property and the onKeyDown event.
This is what I return as a cell: <div id={props.id} tabIndex="0" className={className} onKeyDown={(e)=> {handleKeyDown(e)}}> {value} </div>
And this is how I map through a row to render cells: const cells = rowContent.map((cell, cellIndex) => { return <Cell key={uuid()} solution={props.solution} activeSquare={props.activeSquare} value={cell === "." ? null : cell} id={startNum+cellIndex+1} selected={selected} /> })
Related
I have an API that returns me arrays. I implemented the code to search 3 of them like this:
{response !== undefined &&
search !== "" &&
response.InsuranceServiceList.filter((insurance) =>
insurance.Name.replace(/ي/g, "ی", /ا/, "آ").includes(search)
)
.slice(0, 3)
.map((filtered, i) => (
<EachInsurance
filtered={filtered}
key={i}
styles={scss}
DatePresence={DatePresence}
IdInsurance={IdInsurance}
TimePresence={TimePresence}
/>
))}
whenever user types something in search box, 3 of these matching arrays will get rendered.
but I have two problems with selecting them.
this is each insurance component:
<Container
className={styles.eachInsurance}
style={{
borderRight: `${selectInsurance ? "20px" : "1px"} solid #fcc4de`,
}}
>
<div
onClick={() => {
setSelectInsurance((prev) => !prev);
setCount(0);
}}
>
<p className={styles.NameService}>{filtered.Name.replace(/ي/g, "ی")}</p>
</div>
</Container>
whenever user clicks on element. it will have pinkish border with the width of 20px.
the problem is, when I type another thing to search another item. it shows that Item selected.
just like the clicked div is still there but the content inside of it has changed.
how can I prevent this problem?
I thought it would render a new div per each array. but it wasn't.
the second problem is search itself. if you delete what you've write completely (emptying search bar). everything you have selected before will get removed and you will need to reselect it again.
I want to prevent this too.
You need to pass the id from your back end to your front end. then add a border based on the ids you pass to the selectInsurance, in that way you will know if the element change the border will be gone.
I think for your second problem you can add a new state that will reserve the whole object of the insurance and you first render from that array so every time you re-render your search array your selected insurance array will stay the same so they will remain in your page
I have a table that fills its rows and <td> tags on its own. It does this fine as shown below:
The table is generated by mapping through an array.
{objInnerValues[shopIndex].map((thing, outerIndex) => (
// Ternary operator to stop creating rows from element 0
(outerIndex === 0) ? console.log("outerIndex WAS 0") : (outerIndex %2 === 0) ?
Object.values(thing).map((innerThing, innerIndex) => (
<>
{/* Tooltip popup for item blurb */}
<HtmlTooltip title={
//a tooltip component, from MUI. Gets a string to display
}
>
{/* Table rows for each record */}
<TableRow
//style definitions, then an id for the row...
id = {"rowID-"+thing[0][0]}
>
{AR_RowRefs.push("rowID-"+thing[0][0])}
{/* Indidivual td elements to display each item in a row*/}
<SuperTD NoHoverTD>
{//Items name}
</SuperTD>
<SuperTD NoHoverSmallTxtTD>
{//category the item belongs to}
<Button>
//a visibility button, part of what I'm trying to work on
</Button>
</SuperTD>
<SuperTD NoHoverSmallTxtTD>
{
//Get weight of item from array and format it
}
</SuperTD>
<SuperTD NoHoverSmallTxtTD>
{
//Get price from array and format it
}
</SuperTD>
{/* Checkbox for if item is available */}
<SuperTD>
<input type="checkbox" defaultChecked={innerThing[6]}/>
</SuperTD>
{/* Checkbox for if item is limited */}
<SuperTD>
<input type="checkbox" defaultChecked={innerThing[7]}/>
</SuperTD>
</TableRow>
</HtmlTooltip>
</>
Above my return block I have an array I want to use to store the ID of each table row that is generated. I have a function (fired from an onClick of each visibility button).
I wrote this in my return block, inside the array map:
{AR_RowRefs.push("rowID-"+thing[0][0])}
However, when I save this and it renders, it creates an extra column of data:
I thought that an extra <td> would only render if I put tags around it. This is just a JSX snippet so is there any particular reason its creating its own <td>? Can I still have this snippet push ids to an array without rendering an extra element?
I thought that an extra <td> would only render if I put tags around it. This is just a JSX snippet so is there any particular reason its creating its own <td>?
The browser is attempting to recover from your error of putting a number (which gets converted to a string) as a child of a tr.
Can I still have this snippet push ids to an array without rendering an extra element?
The quick and dirty approach (which I haven't tested) would be to change the expression so it doesn't evaluate as a number.
{void AR_RowRefs.push("rowID-"+thing[0][0])}
The sensible approach would be to split your data manipulation logic and your display logic.
Object.values(thing).map((innerThing, innerIndex) => {
AR_RowRefs.push("rowID-"+thing[0][0]);
return <>
...
</>;
};
I learn React and JavaScript and now I have this problem
Here's a Codesandbox
What happens is like this:
In the Codesandbox at FileEditor.jsx: I mock it like this:
// Mocking the tag list just to test it
const tagMock = ['11111']; // THIS WORKS WITH ONLY ONE ITEM
// Mocking the tag list just to test it
//const tagMock = ["11111", "22222", "33333"]; // THIS DOES NOT WORK WITH MULTIPLE ITEMS
The tagMock that works in the first one with only one array value.
The tagMock that does not work is the one with 3 values.
(when you star sandbox the tagMock with only one array value is use, please change to tagMock with 3 array values to see the error)
If you look further down in FileEditor.jsx you see where tagMock is use like this:
{tagMock.map((tag) => (
<div className="tagInput">
<button
className="btn btn-warning btn-sm"
disabled={false}
key={tag}
type="button"
// onClick={() => remove(skill)}
>
<TagName tag={tag} />
</button>
</div>
))}
Every button created in this map loop have it's own <TagName tag={tag} />
The TagName is a component that is connected to the Redux Store and there
it selected (using reselect), the store tags and then return the tag name only.
The button name text is by so dynamically set like this:
In the image above, the "name2" button text is set" .
The problem is that this does not work if more then 1 button like this:
//const tagMock = ["11111", "22222", "33333"]; // THIS DOES NOT WORK WITH MULTIPLE ITEMS
The error I get is the name is not defend in the tagName.jsx file.
Why does this happen? I understand it's some form of component duplications issue that the map loop can't create the tagName Component as it should, but I can't figure it out.
ok I solved it,
WRONG:
state.global.tags.find(tag => tag.id > ownProps.tag);
RIGHT:
state.global.tags.find(tag => tag.id === ownProps.tag);
I had to generate multiple rows, where each row has a dropdown (Autocomplete) that was searchable through API, and other fields too. All is working perfectly, except when I delete a row from the middle somewhere, just the autocomplete component displays the same value as earlier, however, I get correct data in my state.
So if I had an array with the following items.
And now if I delete Row 2 which is Brite – (500 g), I get this display on the screen.
However, all other items of the rows are correctly displayed, so I'm assuming there is nothing wrong with my logic of handling the array, but due to autocomplete showing wrong value(however it holds the correct object passed into its value prop), it seems that all items have suddenly changed their Qty and prices, and the last item was deleted (instead of 2nd one).
If I sum up the problem, although the component was re-rendered based on new array in the state, that was obtained after deleting a row, autocomplete still displays its previous value which is nowhere is the data now.
<Autocomplete
options={skuItems}
getOptionLabel={option => option.name}
renderInput={params => (
<TextField {...params} label="SKU" variant="outlined" />
)}
value={selectedSkuItems[index]}
onChange={(e, val) => orderItemHandleChange(e, val, index)}
onInputChange={skuSearch}
/> (edited)
The issue resides where you have the map function. The key must be something unique. If it involves the index, is bad. Because you remove items by index and then another item takes that indexes place, and a proper rewrite of the DOM is failing.
As seen bellow:
collection.map((value, index) => { <div key={something unique}> </div>}
I have 2 components. In one component I render map of table rows =>
this is place, where tDs.map is rendered
this.state.dataOld.map(it =>(
<>
<tr onClick={()=>{it.selected_=!it.selected_;this.forceUpdate()}} value={it} key={it.id}>
{this.tDs.map(fnc => fnc(it,this.hide,this))}
</tr>
</>))
dataOld is array of 2 objects
tDs is array like
function(it,hide,a){return !hide.id ? <td>{it.id}</td> : null},
function(it,hide,a){return !hide.category3 ? <td>{it.category3}</td> : null},
function(it,hide,a){return !hide.edit ? <td>
<Button onClick={() => a.setState({edit:!a.state.edit,element:it})}>
</Button>
</td> : null}
the thing i interested in is a.setState({edit:!a.state.edit,element:it})}
I render another component inside of first
<Edit isOpen={this.state.edit} editBack={this.editBack} th={this} element={this.state.element}/>
I transfer my this.state.element to Edit, inside Edit component I'm doing something like this:
elem = {};
componentDidUpdate(){
this.elem = this.props.element
console.log(this.elem)
}
...
<Input onChange={ e => {this.elem.packagingType = e.target.value; console.log(e.target.value)} } ... />
so, the problem is: I transfer this.state.element to Edit component, then in Edit component I make new variable elem and make it be equal to this.props.elem I transferred
the problem starting here, the first, (original, natural) this.state.element is changing, but I dont change dataOld, I dont change any element that has been rendered, I really dont undestand, how it works here.
My guess was about this place
<Edit isOpen={this.state.edit} editBack={this.editBack} th={this} element={this.state.element}/>
I think that when I'm doing element={this.state.element} I somehow connect this 2 things and when I change element inside of Edit, the natural this.state.element is changing too.
Codesandbox example:
https://codesandbox.io/embed/7wk8689op6?fontsize=14
when you press a button near every row, then change data and press cancel, the original data is changing, I dont understand why
I think I understood the question.
When I put an object to the Edit component, and then change an object inside of component, the original object is changing too because I didn't make a new version of this object, but I gave to Edit a link to this object.