所以我有这个Home Component,其中有一个records
状态,我用它来执行records.map()
并返回表中的RecordItem
组件。
function Home() {
const [records, setRecords] = useState<Array<RecordType>>(loadRecords());
const removeRecord = useCallback((record: RecordType) => {
setRecords(records => {
const newRecords = records.filter(rec => rec !== record);
localStorage.setItem('controle_financeiro', JSON.stringify(newRecords));
return newRecords;
});
}, []);
return (
<tbody>
{
records.map((record, index) => <RecordItem key={index} record={record} removeRecord={removeRecord}/>)
}
</tbody>
)
}
还有一个RecordItem
组件,它被Home
组件使用。正如你所看到的,有一个按钮,它在点击时执行removeRecord
函数。该函数作为props传递,因此在Home
组件中,它是一个memoized函数。
function RecordItem({record, removeRecord}: RecordProps) {
console.log('Renderized RecordItem'); // if there is 50 items in the `records` state array, it will print 50x
return (
<tr>
<td>{record.description}</td>
<td>{record.value}</td>
<td>{record.type === 'in' ? <FaRegArrowAltCircleUp className='in-icon'/> : <FaRegArrowAltCircleDown className='out-icon'/>}</td>
// button that executes the removeRecord function
<td> <FaTrash className='remove-icon' onClick={e => removeRecord(record)}/> </td>
</tr>
)
};
export default memo(RecordItem);
所以,如果在records
状态下有50个项目,在Home组件中,它将在控制台中打印Renderized RecordItem
50x。它再次呈现整个数组,我不想要它。我做错了什么吗?
2条答案
按热度按时间d4so4syb1#
问题是你使用索引作为键。
假设你删除了数组中的第一个元素。你希望react从页面中删除第一个元素,其余的元素保持不变,但是键告诉你要做别的事情。在一个渲染器上,有一个50个元素的列表,键为0-49,然后在下一个渲染器上,有一个49个元素的列表,键为0-48。基于此,react将删除 last 元素,因为这是唯一一个钥匙不在那里的人。对于所有其他的钥匙, prop 已经改变了:键0得到了原来在键1中的记录,键1得到了键2的记录,以此类推。所以所有这些组件都得到了新的 prop ,打破了它们的备忘录。
为了解决这个问题,你需要在你的记录上有一些唯一的标识符,并使用它作为键。如果你已经在
RecordType
上有一个值,使用它。如果没有,你需要添加一个。也许loadRecords
函数可以做到这一点。hwamh0ep2#
不要使用
index
作为关键字。在这种情况下,如果您通过单击按钮删除一个项目,则所有项目都会重新呈现。因为索引已更改。因此您必须使用其他唯一数据作为关键字。record
是否具有唯一ID或其他内容?。