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

Posted

技术标签:

【中文标题】如何从 React 状态数组中删除组件而不删除数组的其余部分?【英文标题】:How do I delete a component from a React state array without deleting rest of array? 【发布时间】:2021-03-23 17:23:07 【问题描述】:

我已经制作了一个基本的应用程序来练习 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;
    当我通过单击按钮添加项目时,父状态会正确更新。 当我单击项目(删除它)时,它会删除自身,但也会删除数组中出现在它之后的每个项目 我也用数字对其进行了测试(不是创建单独的组件)。这些删除正确 - 仅删除我单击的单个数字。

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

当 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 这样会导致以后要删除多个项目:1)创建5个项目(id分别为0、1、2、3、4)——2)删除第3个项目(id 2) -- 3) 再添加两个项目(id 现在是 0、1、3、4、4、5) 【参考方案1】:

问题在于您的deleteItem 函数是旧itemList 的闭包,从创建项目的那一刻开始。两种解决方案:

使用setItemList的回调形式 不要在该列表中存储 react 元素,而只是简单的对象(您可以将其用作道具)并仅在渲染 ListItems 时传递(最新的)deleteItem 函数

【讨论】:

谢谢Bergi,已经解决了!仅供参考,我使用了普通对象方法。我会为遇到同样问题的其他人更新我的原始帖子。

以上是关于如何从 React 状态数组中删除组件而不删除数组的其余部分?的主要内容,如果未能解决你的问题,请参考以下文章

从嵌套对象中删除数据而不改变

如何更改数组状态容器中的对象属性? React Hooks 使用状态

试图从 React 中的对象数组中删除一个项目

使用功能组件/挂钩从 React 中的数组中删除特定项目

如何从 React Js 中的数组属性中删除单个对象?

React Hooks - 从 DOM 中临时删除组件而不卸载它的最佳方法