[英]How can I delete an item from list without re-rendering undeleted Items?
感谢您的所有评论和有用的评论。 按照您的建议,请在下面找到代码沙箱链接
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 次
所以,如果你想最小化项目的重新渲染,你需要确保一些事情
你可以在你想要的组件上使用React.memo
,这将防止在 props/state 没有改变时重新渲染。
所以,使用
export default React.memo(Item);
代替
export default Item;
当您渲染Item
组件时,您将deleteItem
作为 prop 传递,其值是从App
组件接收的。 但是,这个函数不是一个稳定的(每次 App 组件渲染时都会重新定义它。并且由于App
持有items
状态,因此每次删除后都会重新渲染。这将触发一个新的deleteItem
被定义,这将导致要重新渲染的Item
。
为了使这个稳定,你需要两件事。
React.useCallback
,当它的依赖关系保持不变时,它会重用相同的函数。setItems
的function
形式所以,而不是
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>
);
})}
更新了所有更改的代码沙盒: https ://codesandbox.io/s/twilight-water-9iyobx
听起来您想遍历对象数组以在表中生成数据行,每行中的最后一个单元格是删除该行的“删除”按钮。 你可以做到这一点。 不需要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>
更新状态时,您需要先传播先前的状态,然后再对其进行更新示例:
const deleteItem = (newItem) => {
const newItemList = items.filter(item => item.reference !== newItem.reference);
setItems(prev => (...prev, newItemList));
}
更新状态时,您需要先传播先前的状态,然后再更新它
并且取决于您的类型,您必须返回数组或对象 spreat 运算符打开先前的数组或对象,然后添加新数据 setItems(prev => [...prev, newItemList])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.