reactjsreact-hooksusecallback

memoize react component callback in a list


How can I memoize a callback generated in the map loop? This (obviously) gives an error:

const SomeComponent = ({ items }: { items: ItemData[] }) => {
  const getItemCallback = (item: ItemData) => (e: React.MouseEvent) => {
    e.preventDefault();

    //do something with item
  }

  return <div>
    {items.map(item => {
      const callback = useCallback(getItemCallback(item));
    
      return <Item title={item.title} itemCallback={callback} />
    })}

  </div>
}

enter image description here


Solution

  • Wrap getItemCallback in useCallback and pass it to the component:

    const SomeComponent = ({ items }: { items: ItemData[] }) => {
      const getItemCallback = useCallback((item: ItemData) => (e: React.MouseEvent) => {
        e.preventDefault();
    
        //do something with item
      }, []);
    
      return <div>
        {items.map(item => (
          <Item 
            key={item.key}
            item={item} 
            itemCallback={getItemCallback} 
            />
        ))}
      </div>
    }
    

    The component then calls the callback, and passes the item to create a new function wrapped with useCallback:

    const Item = ({ item, itemCallback }) => {
      const callback = useCallback(itemCallback(item), []);
      
      return (
        ...
      );
    }