React memo components and re-render when passing function as props

rodrigocfd picture rodrigocfd · Jan 25, 2019 · Viewed 10.1k times · Source

Suppose I have these React components:

const Compo1 = ({theName}) => {
  return (
    <Nested foo={() => console.log('Dr. ' + theName)}/>
  );
};

const Compo2 = ({theName}) => {
  function theFoo() {
    console.log('Dr. ' + theName);
  }
  return (
    <Nested foo={theFoo}/>
  );
};

And the nested component, wrapped in memo:

const Nested = React.memo(({foo}) => {
  return (
    <Button onClick={foo}>Click me</Button>
  );
});

Function passed in foo is always recreated in Compo1 and also Compo2, correct?

If so, since foo receives a new function every time, does it mean memo will be useless, thus Nested will always be re-rendered?

Answer

Artur Khrabrov picture Artur Khrabrov · May 30, 2019

You can use new hooks Api(React >= 16.8) to avoid recreating callback func.

Just using useCallback hook for this.

For e.g

Parent component

import React, { useCallback} from 'react';

const ParentComponent = ({theName}) => {
  const theFoo = () => {
    console.log('Dr. ' + theName);
  }

  const memoizedCallback = useCallback(theFoo , []);

  return (
     <Nested foo={memoizedCallback}/>
   );
};

useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed (which passed in the second argument) In this case we pass empty array as dependencies and therefore the function will be created only once.

And nested component:

import React, { memo } from 'react';

const Nested = ({foo}) => (
  <Button onClick={foo}>Click me</Button>
);

export default memo(Nested);

For more info - https://reactjs.org/docs/hooks-reference.html#usecallback