React useState возвращает старое значение

#reactjs #react-hooks #use-state

#reactjs #реагирующие крючки #состояние использования

Вопрос:

В следующем примере я отображаю три элемента: 1, 2, 3. Я нажимаю на элемент 3, чтобы удалить его, однако на экране остаются элементы 2 и 3, а не только 1 и 2, поскольку элемент 3 должен был быть удален. Почему элемент 3 не удален?

Вот ссылка codesandbox, нажатие на 3 должно удалить ее: https://codesandbox.io/s/eager-currying-1bxnb?file=/src/App.js

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

export default function App() {
  const [items, setItems] = useState(data);

  const onDelete = (id) => {

    //LOGGING
    console.log(`^^^^^^^^^^BEFORE DELETING^^^^^^^^^^^^^^^^`)
    items.forEach( i => console.log(i.title))
    console.log(`-----------------------------------------`)

    //LOGIC
    let filteredItems = items.filter((c) => c.id != id);
    setItems([...filteredItems]);

    //LOGGING
    console.log(`^^^^^^^^^^AFTER DELETING^^^^^^^^^^^^^^^^`)
    filteredItems.forEach( i => console.log(i.title))
    console.log(`-----------------------------------------`)
  };

  return (
    <div>
      {items.map((i) => (
        <Item id={i.id} title={i.title} onDelete={onDelete} />
      ))}
    </div>
  );
}

const data = [
  {
    id: 3,
    uuid: "dbc74622-7002-41d2-9d89-e3d0d4558d25",
    title: "Item 3"
  },
  {
    id: 2,
    uuid: "c7ac4c96-c1e0-45a4-a739-6ca4ad483b68",
    title: "Item 2"
  },
  {
    id: 1,
    uuid: "48c90e0b-5b09-4583-8665-1f3d6f9df5f1",
    title: "Item 1"
  }
];

const Item = ({ id, title, onDelete }) => {

  console.log(`Rendering Item ${title}`)
  const [inputTitle, setTitle] = useState(title);
  console.log(`Value set in useState ${inputTitle}`)
  // ^ this is where the problem occurs even though I set "Item 2", this returs "Item 3"

  return (
    <div
      onClick={() => {
        onDelete(id);
      }}
      key={id}
    >
      <h3>{inputTitle}</h3>
    </div>
  );

};
 

Комментарии:

1. Не могли бы вы пояснить, почему порядок имеет значение? Если я удалил элемент из массива, он не должен присутствовать.

Ответ №1:

key Prop должен идти на <Item> компонент в вашем items.map() обратном вызове, а не на <div> элемент, у которого нет братьев и сестер. Это необходимо для того, чтобы React мог определить, какой Item экземпляр в виртуальном DOM связан с каждым соответствующим элементом вашего items массива.

В качестве примечания, вам не нужно распространяться filteredItems при вызове setItems() , поскольку items.filter() метод уже возвращает новый экземпляр массива, поэтому setItems(filteredItems); достаточно.