reactjsreduxreact-hookshigher-order-components

useCallback for function that incorporates batched redux actions (from HOC). What shall i put in the dependancy array?


I have this component

import React from 'react';
import { batch } from 'react-redux';  
  
const ContextMenu = ({
      menuData,
      isOpen,
      changeIsMenuOpen,
      changeAssetType,
    }) => {
      return (
        <ClickAwayListener
          onClickAway={() => {
            batch(() => {
              changeIsMenuOpen(false);
              changeAssetType(null);
            });
          }}
        >
          <ContextMenu
            open={isOpen}
            menuData={menuData}
          />
        </ClickAwayListener>
      );
    };

that gets its props from following HOC

export default connect(
  state => ({
    isOpen: selectors.getIsMenuOpen(state),
    menuData: selectors.getMenuData(state),
  }),
  {
    changeIsMenuOpen: actions.changeIsMenuOpen,
    changeAssetType: actions.changeAssetType,
  },
)(ContextMenu);

I thought it might be a good idea to put onClickAway listener to useCallback, so that its instance wont be recreated in every render. Something like

const handleClickAway = useCallback(() => {
    batch(() => {
      changeIsMenuOpen(false);
      changeAssetType(null);
    });
  }, []);

but i'm not sure what I must put into the dependency array. Should it be all the methods I am using? Something like

[batch, changeIsMenuOpen, changeAssetType]

Solution

  • You should only memoize something when it is actually affecting the application performance.

    With that being said, to memoize a function using useCallback, you need to pass in all the external items you are using in the function.

    So, [batch, changeIsMenuOpen, changeAssetType] is a correct dependency array.

    batch is coming from a library. Also, changeIsMenuOpen and changeAssetType seem to be redux actions. So, most likely, they are going to be stable. However, one thing to note is that, if you use some object/function from props which is not memoized, then your memoization is essentially useless since the function will be recreated on every render. In fact, as there are additional checks to maintain a memoized function, your application would have performed slightly better without the memoization.

    As a rule of thumb, only memoize things, if re-rendering is costly. Make use of the React's Profiler (https://reactjs.org/docs/profiler.html)