如何在不重新呈现未删除项目的情况下从列表中删除项目?

How can I delete an item from list without re-rendering undeleted Items?

感谢您的所有评论和有益的评论。 按照您的建议,请在下面找到一个代码沙箱 link

https://codesandbox.io/s/magical-butterfly-uk0fjq?file=/src/item.js

这可能会帮助您解决问题。 console 中的一切都很明显,有多个日志,考虑到示例的当前规模,这不会造成任何性能问题,但如果有很长的项目列表,这可能会造成影响。

所以问题是,尽管父级 (ItemList) 重新呈现,但如何继续防止未删除的项目重新呈现。

console 显示 Item 渲染。

如前所述,我使用了useMemo + useCallback组合,但结果证明不稳定。

希望这个例子能有所帮助并且更明确。

编辑

关于 console log,奇怪的是,沙箱示例记录了 2 次 App、2 次 ItemList 和 12 次 Item,而在它只记录 1-1-6 次的计算机

更新状态时需要先传播之前的状态再更新 示例:

const deleteItem = (newItem) => {
  const newItemList = items.filter(item => item.reference !== newItem.reference);
  setItems(prev => (...prev, newItemList));
}

更新状态时需要先传播之前的状态再更新

并且取决于您的类型,您必须 return 数组或对象 spreat 运算符打开了先前的数组或对象,然后您添加了新数据 setItems(prev => [...prev, newItemList])

听起来就像您想遍历对象数组以在table中生成数据行,每行中的最后一个单元格是“删除”按钮,删除该行。你可以做到。不需要 useEffect.

const { useState } = React;

// Pass in the data
function Example({ data }) {

  // Set the state with the data
  const [ tableData, setTableData ] = useState(data);

  // When a remove button is clicked `filter`
  // out those rows that don't match the row id
  // and reset the state
  function handleRemove(e) {
    const { id } = e.target.closest('tr').dataset;
    const filtered = tableData.filter(obj => {
      return obj.name !== id;
    });
    setTableData(filtered);
  }

  // Create some rows by mapping over the
  // table data
  return (
    <table>
      {tableData.map(row => {
        return (
          <Row
            key={row.name}
            row={row}
            handleRemove={handleRemove}
          />
        );
      })}
    </table>
  );

}

// Create a table row and populate the cells
// with the information from the row object
function Row({ row, handleRemove }) {
  return (
    <tr data-id={row.name}>
      <td>{row.name}</td>
      <td>{row.reference}</td>
      <td>{row.description}</td>
      <td>
        <button
          onClick={handleRemove}
        >Remove
        </button>
      </td>
    </tr>
  );
}

const data = [
 {name: "NAME 1", reference: "REF 1", description: "LOREM IPSUM"},
 {name: "NAME 2", reference: "REF 2", description: "LOREM IPSUM"},
 {name: "NAME 3", reference: "REF 3", description: "LOREM IPSUM"},
 {name: "NAME 4", reference: "REF 4", description: "LOREM IPSUM"},
 {name: "NAME 5", reference: "REF 5", description: "LOREM IPSUM"}
];

ReactDOM.render(
  <Example data={data} />,
  document.getElementById('react')
);
table { border-collapse: collapse; border: 1px solid #565656; }
td { border: 1px solid #dfdfdf; padding: 0.5em;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

所以,如果你想最小化项目的 re-renders,你需要确定一些事情

记忆组件

你可以在你想要的组件上使用React.memo,当props/state不改变时,这将防止re-renders。

所以,使用

export default React.memo(Item);

而不是

export default Item;

确保道具相同

渲染 Item 组件时,您将 deleteItem 作为道具传递,其值是从 App 组件接收的。但是,这个函数并不稳定(每次 App 组件渲染时都会重新定义。并且由于 App 保持 items 状态,因此每次删除后都会重新渲染。这将触发新的 deleteItem 被定义,这将导致 Item 到 re-render.

要使其稳定,您需要做两件事。

  1. 使用 React.useCallback re-uses 在其依赖项保持不变的情况下具有相同的功能。
  2. 使用setItemsfunction form

所以,而不是

const deleteItem = (newItem) => {
  const newItemList = items.filter(
    (item) => item.reference !== newItem.reference
  );
  setItems(newItemList);
};

使用

const deleteItem = React.useCallback((itemToDelete) => {
  setItems((currentItems) =>
    currentItems.filter((item) => item.reference !== itemToDelete.reference)
  );
}, []);

你的代码也有问题,你 .map 数据但是然后在 returning 每个 Item 之前你将它推入一个数组并且 return那反而。只是 return <Item ..>

所以不用

    {props.data.map((item, index) => {
      const newList = [];
      newList.push(
        <Item
          deleteItem={props.deleteItem}
          key={item.reference}
          item={item}
        ></Item>
      );
      return newList;
    })}

    {props.data.map((item, index) => {
      return (
        <Item
          deleteItem={props.deleteItem}
          key={item.reference}
          item={item}
        ></Item>
      );
    })}

已更新的代码和框包含所有更改:https://codesandbox.io/s/twilight-water-9iyobx