Saturday, May 14, 2022
HomeWebsite DesignThe best way to Implement Memoization in React to Enhance Efficiency

The best way to Implement Memoization in React to Enhance Efficiency


On this tutorial, we’ll learn to implement memoization in React. Memoization improves efficiency by storing the outcomes of high-priced perform calls and returning these cached outcomes after they’re wanted once more.

We’ll cowl the next:

  • how React renders the UI
  • why there’s a necessity for React memoization
  • how we will implement memoization for purposeful and sophistication parts
  • issues to remember relating to memoization

This text assumes you have got a primary understanding of sophistication and purposeful parts in React. In the event you’d wish to brush up on these matters, take a look at the official React docs on parts and props.

How React Renders the UI

Earlier than going into the main points of memoization in React, let’s first take a look at how React renders the UI utilizing a digital DOM.

The common DOM principally comprises a set of nodes represented as a tree. Every node within the DOM is a illustration of a UI aspect. Every time there’s a state change in your software, the respective node for that UI aspect and all its youngsters get up to date within the DOM after which the UI is re-painted to replicate the up to date modifications.

Updating the nodes is quicker with the assistance of environment friendly tree algorithms, however the re-painting is gradual and may have a efficiency influence when that DOM has a lot of UI components. Due to this fact, the digital DOM was launched in React.

This can be a digital illustration of the true DOM. Now, each time there’s any change within the software’s state, as a substitute of straight updating the true DOM, React creates a brand new digital DOM. React then compares this new digital DOM with the beforehand created digital DOM to search out the variations that should be repainted.

Utilizing these variations, the digital DOM will replace the true DOM effectively with the modifications. This improves efficiency, as a result of as a substitute of merely updating the UI aspect and all its youngsters, the digital DOM will effectively replace solely the mandatory and minimal modifications in the true DOM.

Why We Want Memoization in React

Within the earlier part, we noticed how React effectively performs DOM updates utilizing a digital DOM to enhance efficiency. On this part, we’ll take a look at a use case that explains the necessity for memoization for additional efficiency enhance.

We’ll create a mum or dad class that comprises a button to increment a state variable referred to as rely. The mum or dad element additionally has a name to a baby element, passing a prop to it. We’ve additionally added console.log() statements in render the strategy of each the courses:


class Father or mother extends React.Part {
  constructor(props) {
    tremendous(props);
    this.state = { rely: 0 };
  }

  handleClick = () => {
    this.setState((prevState) => {
      return { rely: prevState.rely + 1 };
    });
  };

  render() {
    console.log("Father or mother render");
    return (
      <div className="App">
        <button onClick={this.handleClick}>Increment</button>
        <h2>{this.state.rely}</h2>
        <Youngster identify={"joe"} />
      </div>
    );
  }
}

export default Father or mother;

The whole code for this instance is offered on CodeSandbox.

We’ll create a Youngster class that accepts a prop handed by the mum or dad element and shows it within the UI:


class Youngster extends React.Part {
  render() {
    console.log("Youngster render");
    return (
      <div>
        <h2>{this.props.identify}</h2>
      </div>
    );
  }
}

export default Youngster;

Every time we click on the button within the mum or dad element, the rely worth modifications. Since this can be a state change, the mum or dad element’s render methodology is named.

The props handed to the kid class stay the identical for each mum or dad re-render, so the kid element shouldn’t re-render. But, once we run the above code and maintain incrementing the rely, we get the next output:

Father or mother render
Youngster render
Father or mother render
Youngster render
Father or mother render
Youngster render

You possibly can increment the rely for the above instance your self within the following sandbox and see the console for the output:


From this output, we will see that, when the mum or dad element re-renders, it’s going to additionally re-render the kid element — even when the props handed to the kid element are unchanged. It will trigger the kid’s digital DOM to carry out a distinction verify with the earlier digital DOM. Since we have now no distinction within the little one element — because the props are the identical for all re-renders — the true DOM isn’t up to date.

We do have a efficiency profit the place the true DOM isn’t up to date unnecessarily, however we will see right here that, even when there was no precise change within the little one element, the brand new digital DOM was created and a distinction verify was carried out. For small React parts, this efficiency is negligible, however for big parts, the efficiency influence is critical. To keep away from this re-render and digital DOM verify, we use memoization.

Memoization in React

Within the context of a React app, memoization is a method the place, each time the mum or dad element re-renders, the kid element re-renders provided that there’s a change within the props. If there’s no change within the props, it received’t execute the render methodology and can return the cached end result. Because the render methodology isn’t executed, there received’t be a digital DOM creation and distinction checks — thus giving us a efficiency enhance.

Now, let’s see easy methods to implement memoization at school and purposeful React parts to keep away from this pointless re-render.

Implementing Memoization in a Class Part

To implement memoization in a category element, we’ll use React.PureComponent. React.PureComponent implements shouldComponentUpdate(), which does a shallow comparability on state and props and renders the React element provided that there’s a change within the props or state.

Change the kid element to the code proven beneath:


class Youngster extends React.PureComponent { 
  render() {
    console.log("Youngster render");
    return (
      <div>
        <h2>{this.props.identify}</h2>
      </div>
    );
  }
}

export default Youngster;

The whole code for this instance is proven within the following sandbox:


The mum or dad element stays unchanged. Now, once we increment the rely in mum or dad element, the output within the console is as follows:

Father or mother render
Youngster render
Father or mother render
Father or mother render

For the primary render, it calls each mum or dad and little one element’s render methodology.

For subsequent re-render on each increment, solely the mum or dad element’s render perform is named. The kid element isn’t re-rendered.

Implementing Memoization in a Practical Part

To implement memoization in purposeful React parts, we’ll use React.memo().React.memo() is a larger order element (HOC) that does an identical job to PureComponent, avoiding pointless re-renders.

Beneath is the code for a purposeful element:


export perform Youngster(props) {
  console.log("Youngster render");
  return (
    <div>
      <h2>{props.identify}</h2>
    </div>
  );
}

export default React.memo(Youngster); 

We additionally convert the mum or dad element to a purposeful element, as proven beneath:


export default perform Father or mother() {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount(rely + 1);
  };
  console.log("Father or mother render");
  return (
    <div>
      <button onClick={handleClick}>Increment</button>
      <h2>{rely}</h2>
      <Youngster identify={"joe"} />
    </div>
  );
}

The whole code for this instance will be seen within the following sandbox:


Now, once we increment the rely within the mum or dad element, the next is output to the console:

Father or mother render
Youngster render
Father or mother render
Father or mother render
Father or mother render

The Drawback with React.memo() for Perform Props

Within the above instance, we noticed that once we used the React.memo() HOC for the kid element, the kid element didn’t re-render, even when the mum or dad element did.

A small caveat to concentrate on, nonetheless, is that if we move a perform as prop to little one element, even after utilizing React.memo(), the kid element will re-render. Let’s see an instance of this.

We’ll change the mum or dad element as proven beneath. Right here, we’ve added a handler perform that we’ll move to the kid element as props:


export default perform Father or mother() {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount(rely + 1);
  };

  const handler = () => {
    console.log("handler");    
  };

  console.log("Father or mother render");
  return (
    <div className="App">
      <button onClick={handleClick}>Increment</button>
      <h2>{rely}</h2>
      <Youngster identify={"joe"} childFunc={handler} />
    </div>
  );
}

The kid element code stays as it’s. We don’t use the perform we’ve handed as props within the little one element:


export perform Youngster(props) {
  console.log("Youngster render");
  return (
    <div>
      <h2>{props.identify}</h2>
    </div>
  );
}

export default React.memo(Youngster);

Now, once we increment the rely in mum or dad element, it re-renders and in addition re-renders the kid element, though there’s no change within the props handed.

So, what brought about the kid to re-render? The reply is that, each time the mum or dad element re-renders, a brand new handler perform is created and handed to the kid. Now, because the handler perform is recreated on each re-render, the kid, on a shallow comparability of props, finds that the handler reference has modified and re-renders the kid element.

Within the subsequent part, we’ll see easy methods to repair this problem.

useCallback() to Keep away from Additional Re-rendering

The principle problem that brought about the kid to re-render is the recreation of the handler perform, which modified the reference handed to the kid. So, we have to have a technique to keep away from this recreation. If the handler isn’t recreated, the reference to the handler received’t change — so the kid received’t re-render.

To keep away from recreating the perform each time when the mum or dad element is rendered, we’ll use a React hook referred to as useCallback(). Hooks have been launched in React 16. To be taught extra about hooks, you possibly can take a look on the React’s official hooks documentation, or take a look at “React Hooks: The best way to Get Began & Construct Your Personal”.

The useCallback() hook takes two arguments: the callback perform, and an inventory of dependencies.

Think about the next instance of useCallback():

const handleClick = useCallback(() => {
  
}, [x,y]);

Right here, useCallback() is added to the handleClick() perform. The second argument [x,y] might be an empty array, a single dependency, or an inventory of dependencies. Every time any dependency talked about within the second argument modifications, solely then will the handleClick() perform be recreated.

If the dependencies talked about in useCallback() don’t change, a memoized model of the callback that’s talked about as the primary argument is returned. We’ll change our mum or dad purposeful element to make use of the useCallback() hook for the handler that’s handed to the kid element:


export default perform Father or mother() {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount(rely + 1);
  };

  const handler = useCallback(() => { 
    console.log("handler");
  }, []);

  console.log("Father or mother render");
  return (
    <div className="App">
      <button onClick={handleClick}>Increment</button>
      <h2>{rely}</h2>
      <Youngster identify={"joe"} childFunc={handler} />
    </div>
  );
}

The kid element code stays as it’s.

The whole code for this instance is proven beneath:


After we increment the rely within the mum or dad element for the code above, we will see the next output:

Father or mother render
Youngster render
Father or mother render
Father or mother render
Father or mother render

Since we used the useCallback() hook for the mum or dad handler, each time the mum or dad re-renders, the handler perform received’t be recreated, and a memoized model of the handler is distributed all the way down to the kid. The kid element will do a shallow comparability and see that handler perform’s reference hasn’t modified — so it received’t name the render methodology.

Issues to Bear in mind

Memoization is an efficient approach for bettering efficiency in React apps by avoiding pointless re-renders of a element if its props or state haven’t modified. You may consider simply including memoization for all of the parts, however that’s not a great way to construct your React parts. It’s best to use memoization solely in instances the place the element:

  • returns the identical output when given the identical props
  • has a number of UI components and a digital DOM verify will influence efficiency
  • is commonly offered the identical props

Conclusion

On this tutorial, we’ve seen:

  • how React renders the UI
  • why memoization is required
  • easy methods to implement memoization in React by way of React.memo() for a purposeful React element and React.PureComponent for a category element
  • a use case the place, even after utilizing React.memo(), the kid element will re-render
  • easy methods to use the useCallback() hook to keep away from re-rendering when a perform is handed as props to a baby element.

I hope you’ve discovered this introduction to React memoization helpful!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments