I’m using NextJs and React to create a form. I have an input box that gets created with a button click. There can be multiple input boxes. To delete the input box, you click the delete button next to it.
The issue is: if you click Delete on one row, it will delete that row and all the rows after it.
E.g. if you click delete on row 2, it will delete row 2 and three. if you click delete on row 1, it will delete all the rows. If there are 10 rows, and you delete row 4, there will only be 3 rows.
I saw a similar similar Stackoverflow where it said to not use the length because the length kept changing but that does not seem to be the case here. I changed the ID to be a timestamp from new Date.getTime()
.
Here’s my parent component:
export default function CmdBuilder() {
const [cmdNodes, setCmdNodes] = React.useState([]);
function addRow() {
setCmdNodes(
cmdNodes.concat(
<CmdNode key={new Date().getTime()} uniqueId={new Date().getTime()} onRemove={(id) => removeNode(id)} />
));
}
function removeNode(id) {
setCmdNodes((nodes) => cmdNodes.filter((node) => node.uniqueId != id));
);
}
return (
<div id='cmdBuilder'>
{cmdNodes}
<button onClick={addRow}>Add Row</button>
</div>
)
}
Here is my child component:
export default function CmdNode(props) {
return (
<div className={styles.builderGroup} id={props.uniqueId}>
<input type='text' className={styles.cmdText} />
<button className={styles.cmdDelete} onClick={() => props.onRemove(props.uniqueId)}>Delete</button>
</div>
)
}
What could I be missing? The logic seems right but please let me know if I’m missing something fundamental.
Edit: I’ve verified that the key and uniqueId values match, if that matters. I’ve also verified that the selected row’s uniqueId is correct.
2
Answers
In your
removeNode
you are passing a function tosetState
which is fine. React will pass the component’s current state as a parameter to this function. In your definition you have named this parameternodes
, but then you refer tocmdNodes
in the function body instead of nodes. Simply changeto
The first version doesn’t work because the value of
cmdNodes
is bound to the function closure at the time when the function is defined; it’s not actually deleting all the components after it, you’re just accidentally resetting state to the value it had whenonRemove
was initialized.You could probably just set the value of
setCmdNodes
as well. I haven’t tested it but it would avoid some of this closure nonsense.Don’t put component instances in state, put data in state and render components:
You also had a typo where you weren’t using
nodes
inremoveNode
– look for the unused variable low-lighting in your IDE to catch bugs of that sort.