Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent re-render when sending function prop from functional component

When sending props to a PureComponent or a functional component, you can optimize performance by using props that don't change for every render, which will prevent the component from re-rendering.

When using class components this is simple:

class Component extends React.Component {
  render() {
    return <List createRows={this.createRows}/>;
  }

  createRows = () => this.props.data.map(dataToRow);
}

Given List being either a PureCompoment or a functional component, the createRows prop will never cause a re-render of List.


But if the Component is a functional component, this is no longer possible:

  function Component(props) {
    return <List createRows={createRows}/>;

    function createRows() {
      return props.data.map(dataToRow);
    }
  }

Since createRows is created every time Component renders, the prop will change, causing a re-render of List every time Component is re-rendered. This can cause a big loss in performance. Notice also that the createRows cannot be placed outside the functional component, since it is dependent on the data prop of List.


Now, with the introduction on Hooks, it is possible to hold the createRows in a useState hook:

  function Component(props) {
    const [ createRows ] = useState(() => () =>
      props.data.map(dataToRow);
    );

    return <List createRows={createRows}/>;
  }

Since the createRows is saved in a state hook, it will not change with each render, and no re-render of List will occour, like we want.

However, this seems more like a hack than a solution.


What is best practice for sending a function prop from a functional components to a child component, without causing unnecessary re-renders of the child component?

like image 210
darksmurf Avatar asked Apr 01 '19 14:04

darksmurf


2 Answers

useCallback hook exists exactly to solve this problem. I advise you to carefully read the official guide to hooks, it pretty much answers all possible questions

  function Component(props) {
    const createRows = useCallback(() =>
      props.data.map(dataToRow);
    ), []); // provide dependencies here

    return <List createRows={createRows}/>;
  }
like image 157
GProst Avatar answered Nov 16 '22 19:11

GProst


This is the purpose of useCallback. You can find more details in some of my related answers below.

Trouble with simple example of React Hooks useCallback

What is the intension of using React's useCallback hook in place of useEffect?

React Hooks useCallback causes child to re-render

like image 45
Ryan Cogswell Avatar answered Nov 16 '22 17:11

Ryan Cogswell