如何从列表中删除项目而不重新呈现未删除的项目?



感谢大家的评论和帮助。按照你的建议,请找到下面的代码沙盒链接

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

可以帮助你找出问题所在。在console中,一切都很明显,具有多个日志,考虑到示例的当前规模,这不会造成任何性能问题,但如果有一个很长的项目列表,则可能会造成性能问题。

所以问题是,如何继续防止未被删除的项目重新渲染,尽管父(ItemList)重新渲染。

consoleItem渲染。

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

希望这个例子能帮助你更明确。

编辑

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

所以,如果你想尽量减少项目的重新渲染,你需要确保一些事情

记忆组件

你可以在你想要的组件上使用React.memo,这将防止在道具/状态没有改变时重新渲染。

所以,使用

export default React.memo(Item);

不是

export default Item;

确保道具是相同的

当你渲染Item组件时,你传递deleteItem作为一个道具,它的值是从App组件接收的。然而,这个函数并不是一个稳定的函数(每次App组件呈现时它都会被重新定义)。由于App保持items状态,它将在每次删除后呈现。这将触发一个新的deleteItem被定义,这将导致Item重新渲染。

要使其稳定,需要两个条件。

  1. 使用React.useCallback,它在依赖项保持不变的情况下重用相同的函数。
  2. 使用setItems
  3. function形式

so,而不是

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数据,但在返回每个Item之前,你把它推到一个数组中,然后返回它。只需要返回<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>
);
})}

更新codesandbox与所有的变化:https://codesandbox.io/s/twilight-water-9iyobx

听起来就像您想要迭代您的对象数组以生成表中的数据行,并且每行中的最后一个单元格是&;remove&;按钮,该按钮删除行。你可以这么做。不需要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>

当更新状态时,您需要在更新之前先传播先前的状态

取决于你的类型,你必须返回数组或对象扩展操作符打开先前的数组或对象,然后添加新数据setItems (prev =比;[…上一页,newItemList])

更新状态时,需要先展开之前的状态,然后再更新它例子:

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

最新更新