So i have this Home Component, where there is a records
state, i use it to perform a records.map()
and return RecordItem
components inside the table.
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>
)
}
And there is the RecordItem
component, that is used by the Home
component.
As you can see, there is a button, that executes the removeRecord
function on click.
That function is passed as props, so in the Home
component, it is a memoized function.
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);
So, if there is 50 items in the records
state, in the Home component, it will print in the console Renderized RecordItem
50x.
It render the entire array again, i don’t want it. I did anything wrong?
2
Answers
The issue is that you’re using the index as a key.
Suppose you delete the first item in the array. You’re expecting react to remove the first item from the page, and leave the rest unchanged, but the keys say to do something else. On one render there’s a list of 50 items with keys 0-49, then on the next render there’s a list of 49 items with keys 0-48. Based on this, react will remove the last element, because that’s the only one who’s key is not there any more. For all the other keys, the props have changed: key 0 is getting the record that used to be in key 1, key 1 is getting the record from key 2, etc. So all of these components receive new props, breaking their memo.
To fix this, you’ll need some unique identifier on your records, and use that as the key. If you already have a value on
RecordType
, use that. If not, you’ll need to add one. Perhaps theloadRecords
function can do that.don’t use the
index
as a key.In that case, All of items are re-rendered if you remove one by clicking the button. because index is changed.
So you have to use other unique data as a key.
Does
record
has a unique id or something else?.