Removing an item from an array of items only removes the last item

Viewed 273

I am having trouble with deleting some element from an array of React components. I have some simple App, which has only one button "Add form", when user clicks on this button, new Form with firstname and lastname inputes will be added. If user wants to delete this form, user can just click delete button and remove this form from an array. However, the problem is that whenever user click on delete on some form, last element becomes removed all the time. But if you look at the console, you can see that deleted form is removed from state, but in the UI last element removed. Sample code:

import { useState } from "react";
import "./styles.css";

export default function App() {
  const [forms, setForms] = useState([]);

  const addNewForm = () => {
    setForms([
      ...forms,
      {
        valuesOfForm: { firstname: "", lastname: "" }
      }
    ]);
  };

  const handleChangeForms = (name, value, index) => {
    const values = [...forms];
    values[index].valuesOfForm[name] = value;
    setForms([...values]);
  };

  const handleDeleteForms = (index) => {
    const values = [...forms];
    values.splice(index, 1);
    setForms([...values]);
  };

  return (
    <div className="App">
      <div>
        <button onClick={addNewForm}>Add new form</button>
        {console.log(forms)}
        {forms.map((form, index) => (
          <SomeForm
            value={form.valuesOfForm}
            key={index}
            index={index}
            handleChangeForms={handleChangeForms}
            handleDeleteForms={handleDeleteForms}
          />
        ))}
      </div>
    </div>
  );
}

const SomeForm = (props) => {
  const [value, setValue] = useState(props.value);
  const onFormChange = (event) => {
    props.handleChangeForms(event.target.name, event.target.value, props.index);
    setValue({ ...value, [event.target.name]: event.target.value });
  };

  const onClick = (event) => {
    event.preventDefault();
    props.handleDeleteForms(props.index);
  };

  return (
    <form onChange={onFormChange}>
      <input
        type="text"
        name="firstname"
        placeholder="first name"
        onChange={onFormChange}
        value={value.firstname}
      />
      <input
        type="text"
        name="lastname"
        placeholder="last name"
        value={value.lastname}
      />
      <button onClick={onClick}>Delete form</button>
    </form>
  );
};

Sandbox

1 Answers

Because you're using index as key. The key will help react know which one should be updated. So you need to provide a unique value for each component.

FYI: https://reactjs.org/docs/lists-and-keys.html

The quick fix for your example:

let id = 0 // Introduce id variable

export default function App() {

Increase Id each time you add new item:

  const addNewForm = () => {
    id++;
    setForms([
      ...forms,
      {
        id,
        valuesOfForm: { firstname: "", lastname: "" }
      }
    ]);
  };

Change the key to id:

<SomeForm
  value={form.valuesOfForm}
  key={form.id}
  index={index}

Everything will work after this

Related