我正在尝试渲染一个项目列表,每个项目都有一个按钮,该按钮将在按下时切换下拉菜单。
我的代码看起来像:
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>
);
上面的代码有效,但是当用户从列表中添加或删除项目时,废物呈现。(itemClickHandlers
即使只能创建或删除一个处理程序,也会与所有新处理程序生成一个新对象,因此列表中的每个项目都重新订阅了,因为isDropdownExpanded
不会通过参考等式平等。(
最好仅使用函数react组件,当项目列表更改时,我如何用最小的重新呈现此类项目列表?
您不需要数组中的每个项目。您所需要的只是让您在ID上传递一个处理程序,如果您在li
元素上添加ID
function ItemList({items}) {
const [isDropdownExpanded, setIsDropdownExpanded] = useState(null);
const itemClickHandlers = useCallback((e) => {
const id = e.currentTarget.id;
setIsDropdownExpanded(prev => (prev != id ? id: null));
}, [])
return (
<ul>
{items.map(item =>
<li key={item.id} id={item.id} onClick={itemClickHandler}>
<Item name={item.name} isDropdownExpanded={isDropdownExpanded === item.id}/>
</li>
)}
</ul>
);
}