0

So, the problem I've faced is that when I click delete button at any index it just deletes last element for example, if I press first delete button, it should remove first input and the delete button, but what it does is that it deletes last element only... What could be wrong?

function App() {
  const [names, setNames] = React.useState([
    "First",
    "Second",
    "third",
    "fourth"
  ]);

  const onChange= (index: number, editedName: string) => {
    const mutatedNames = [...names];
    mutatedNames[index] = editedName;
    setNames(mutatedNames);
  };

  function onDelete(index: number) {
    const nameArr = [...names];
    nameArr.splice(index, 1);
    setNames(nameArr);
  }


  return (
    <div>
      {names.map((name, index) => (
        <ChildComponent
          key={index}
          name={name}
          index={index}
          onChange={onChange}
          onDelete={onDelete}
        />
      ))}
    </div>
  );
}



const Child = React.memo(
  ({ name, index, onChange, onDelete }) => {
    return (
      <div>
        <input
          onChange={(event) => onChange(index, event.target.value)}
        />
        <button onClick={() => onDelete(index)}>delete</button>
      </div>
    );
  }
);
2
  • I suggest giving the names unique ids/ or using string comparison and using those to filter the array to remove the element that has been 'deleted'. Using the index presents the problem where the target array changes size when an element is removed. Consider an array with 3 elements, if the element was rendered with an index of 0 is deleted, then an attempt to delete an element rendered with index 2 will fail, since now the array being operated on has been shortened by the original delete of the element with index 0. Commented Oct 13, 2020 at 17:21
  • Using an id can sometimes be advantageous in certain situations, but isn't necessarily best practice. The problem you're describing @BooklynDadCore isn't a problem here since the rendered array will always match the array in state. Commented Oct 13, 2020 at 17:42

1 Answer 1

2

You are using a partially controlled input, this is almost never a good idea.

Make it fully controlled like so:

<input
  value={name}
  onChange={(event) => onChange(index, event.target.value)} />

I suggest you read the official guidelines about Forms and Controlled Components and the article about the uncontrolled scenario.

Sign up to request clarification or add additional context in comments.

3 Comments

I've done it so but i have to do this with defaultValue
Then that's probably why you're having issues. In a controlled scenario (when you handle onChange), you need to set value.
The thing is until you use the name the virtual dom would be the same because you are not using the name anywhere in your render, so it will just render for an array with 3 elements so you will see an output like the last element is gone, @MarcellToth good find :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.