如何从React状态数组中删除一个组件而不删除数组中的其余部分?

3

我制作了一个基本应用来练习React,但是当我尝试从状态数组中删除单个组件时,所有在它之后的项也会被删除,这让我很困惑。这是我的基本代码:

App.js:

import React from 'react' 
import Parent from './Parent';
import './App.css';

function App() {
  return (
    <div className="App">
      <Parent />
    </div>
  );
}

export default App;

Parent.js:

import React, { useState } from 'react';
import ListItem from './ListItem';
import './App.css';

function Parent() {
  const [itemList, setItemList] = useState([])
  const [numbers, setNumbers] = useState([])

  const addItem = () => {
    const id = Math.ceil(Math.random()*10000)
    const newItem = <ListItem 
      id={id}
      name={'Item-' + id}
      deleteItem={deleteItem}
    />
    const list = [...itemList, newItem]
    setItemList(list)
  };

  const deleteItem = (id) => {
    let newItemList = itemList;
    newItemList = newItemList.filter(item => {
        return item.id !== id
    })
    setItemList(newItemList);
  }

  const addNumber = () => {
    const newNumbers = [...numbers, numbers.length + 1]
    setNumbers(newNumbers)
  }

  const deleteNum = (e) => {
    let newNumbers = numbers
    newNumbers = newNumbers.filter(n => n !== +e.target.innerHTML)
    setNumbers(newNumbers);
  }

  return (
    <div className="Parent">
      List of items:
      <div>
        {itemList}
      </div>
      <button onClick={addItem}>
        Add item
      </button>
      <div>
        List of numbers:
        <div>
          {numbers.map(num => (
            <div onClick={deleteNum}>{num}</div>
          ))}
        </div>
      </div>
      <button onClick={addNumber}>
        Add number
      </button>
    </div>
  );
};

export default Parent;

ListItem.js:

import React from 'react';
import './App.css';

function ListItem(props) {

  const { id, name, deleteItem } = props;

  const handleDeleteItem = () => {
    deleteItem(id);
  }

  return (
    <div className="ListItem" onClick={handleDeleteItem}>
      <div>{name}</div>
    </div>
  );
};

export default ListItem;
  1. 当我通过点击按钮添加一个项目时,父组件的状态会正确更新。
  2. 当我单击项目(以删除它)时,它会将自己和数组中它之后出现的每个项目都删除 <-- 不想要的行为。我只想删除特定的项目。
  3. 我也使用数字进行了测试(而不是创建单独的组件)。这些数字可以正确删除 - 只有我单击的单个数字被删除。

据我所知,单个项目组件在创建时保存了对父组件状态值的引用。这对我来说似乎是非常奇怪的行为...

当由单独的组件构成时,如何仅从itemList状态数组中删除单个项目?

谢谢

编辑:根据Bergi的指示,我通过将“itemList”状态值转换为对象数组以在更改列表时呈现(重新呈现)来解决了问题:

    const addItem = () => {
      const id = Math.ceil(Math.random()*10000);
      const newItem = {
        id: id,
        name: 'Item-' + id,
      }
      const newList = [...itemList, newItem]
      setItemList(newList)
    }

...

    React.useEffect(() => {

    }, [itemList]);

...

<div className="Parent">
    List of items:
    <div>
        {itemList.map(item => {
        return (<ListItem
            id={item.id}
            name={item.name}
            deleteItem={deleteItem}
        />);
    })}
...

不要使用 Math.ceil(Math.random()*10000) 作为 ID,而应该使用 itemList.length - Bergi
这将导致将来删除不止一个项目:1)创建5个项目(id为0、1、2、3、4)-- 2)删除第3个项目(id为2)-- 3)添加两个项目(现在的id为0、1、3、4、4、5) - CynicalGoldfish
1个回答

2
问题在于你的deleteItem函数是一个闭包,它引用了旧的itemList,即创建该项时的那个列表。有两个解决方案:
  • 使用回调形式的setItemList
  • 不要在列表中存储React元素,而只存储普通对象(可以用作props),并且只在渲染ListItem时传递(最新的)deleteItem函数。

谢谢Bergi,问题已经解决了!顺便说一下,我使用了普通对象的方法。我会更新我的原始帖子,以帮助其他遇到同样问题的人。 - CynicalGoldfish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接