darksmurf
darksmurf

Reputation: 3967

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?

Upvotes: 13

Views: 12009

Answers (2)

GProst
GProst

Reputation: 10227

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}/>;
  }

Upvotes: 16

Related Questions