I am building a react application in which I need to add more input fields by the click of a ‘+’ icon and delete the fields by clicking the ‘x’ icon. I am making use of react states to work on this project.
The issue I am facing arises while I am trying to delete a component using the ‘x’ button. Suppose I had three input fields as follows:
(id = 1) value = val1
(id = 2) value = val2
(id = 3) value = val3
When I am deleting the input field with id = 2, I expect to obtain a state as shown below:
(id = 1) value = val1
(id = 3) value = val3
but What I am obtaining is as follows:
(id = 1) value = val1
(id = 3) value = val2
Here is a simplified version of my code:
let count = 1;
export default function Display() {
//idArray stores the id of each of the input fields I have. It's initial state is set as []
const {idArray, setIdArray} = useContext(Context);
let components = idArray.map((id) => {
return (
<Component id={id} />
);
})
const [description, setDescription] = useState("");
return (
<>
<div id="component-1">
<input
className="className"
id="1"
type="text"
onChange={({detail}) => setDescription(detail.value)}
value={description} placeholder="Enter description"
/>
{components}
</div>
<button
iconName="add-plus"
onClick={() => {
count++;
setIdArray(previousIdArray => [...previousIdArray, count]);
}}
/>
</>
)
}
Here is the simplified code for Components:
export default function Component(props) {
const { idArray, setIdArray } = useContext(Context);
function removeRow(id, idArray, setIdArray) {
const newArray = idArray.filter((i) => i !== id);
setIdArray(newArray);
}
const [description, setDescription] = useState("");
return (
<div id={props.id}>
<input
className="className"
id={props.id}
type="text"
onChange={({detail}) => setDescription(detail.value)}
value={description} placeholder="Enter description"
/>
<button
iconName="cross"
onClick={() => removeRow(props.id, idArray, setIdArray)}
/>
</div>
);
}
I expect the state values for id = 3 to remain as val3 when I am deleting the field with id = 2. Any leads on why this is not happening and how it can be resolved are appreciated.
I referred to this and as you can see I am providing a unique id to the components in my code using the count variable, so that should not be an issue.
3
Answers
You are missing React keys on your mapped
Component
components. React falls back to using the array index as the key and when you remove an element from the middle of the array, the indices don’t change, thus the React keys don’t change. Effectively from React’s point of view only the array length changed, so you are rendering one less element.It is possible that your components are failing to re-render as your removeRow function is passing a shallow copy to setIdArray. You can read more about how filter() works here.
In order to decide wether a component need re-rendering (for non-primitive types) react compares the reference of the passed object to the previous state value via "shallow comparison"
You may have better results with the following removeRow method:
I reviewed your trick completely and I suggested new trick if you wanted.
I hope this work for you
and your
Component
component