React Hooks:记住列表的单击处理程序吗?

时间:2019-06-26 23:10:48

标签: reactjs react-hooks

我正在尝试呈现一个项目列表,每个项目都有一个按钮,按下该按钮将切换下拉菜单。

我的代码如下:

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组件,当项目列表更改时,如何以最少的重新渲染来呈现这样的项目列表?

1 个答案:

答案 0 :(得分:2)

您不需要数组中每个项目的处理程序。您需要做的就是让一个处理程序传递ID,如果您在li元素上添加了ID,则可以从事件中获取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>
    );
}