【问题标题】:React Hooks: memoize click handlers for list?React Hooks:记住列表的单击处理程序?
【发布时间】:2019-11-08 22:37:18
【问题描述】:

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

我的代码如下所示:

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

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    您不需要处理数组中的每个项目。您所需要的只是有一个处理程序,如果您在li 元素上添加 id,您可以将 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>
        );
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-07
      • 1970-01-01
      • 1970-01-01
      • 2017-07-29
      • 2012-09-12
      • 2020-10-19
      相关资源
      最近更新 更多