I am trying to render a list of items, each of which has a button which will toggle a dropdown menu when pressed.
My code looks something like:
function ItemList({items}) {
const [isDropdownExpanded, setIsDropdownExpanded] = useState(null);
const itemClickHandlers = useMemo(() => {
const handlers = {}
items.forEach(item => {
handlers[item.id] = value => setIsDropdownExpanded(value ? item.id : null);
});
return handlers;
}, [items.map(item => item.id).join(',')]);
}
return (
<ul>
{items.map(item =>
<li onClick={itemClickHandlers[item.id]}>
<Item name={item.name} isDropdownExpanded={isDropdownExpanded === item.id}/>
</li>
)}
</ul>
);
The above code works, but wastes renders when the user adds or deletes an item from the list. (itemClickHandlers generates a new object with all new handlers, even though only one handler should be created or removed, so every item in the list re-renders because isDropdownExpanded will not be equal by reference equality.)
Preferably using functional React components only, how can I render a list of items like this with minimal re-renders when the list of items changes?