Understanding React Rendering: Part 2 – Improve rendering in React apps

In the recent post about understanding how React renders components, we presented how React renders UI elements and also raised awareness of the fact that React renders everything when only one state or prop has been updated. That will get our apps slowly rendered if the components are complicated and take a few milliseconds to complete the rendering. In line with the series of rendering in React, we will discuss some techniques to speed up rendering.

What is shallow comparison?

According to React’s official documentation, shallowCompare performs a shallow equality check on the current props and nextProps objects as well as the current state and nextState objects. It does this by iterating on the keys of the objects being compared and returning true when the values of a key in each object are not strictly equal.

shallowCompare returns true if the shallow comparison for props or state fails and therefore the component should update.
shallowCompare returns false if the shallow comparison for props and state both pass and therefore the component does not need to update.

Shallow comparison is a process in React to compare the current state or props of a component to the previous one to determine whether they are dirty or not. React performs a shallow comparison by comparing the reference values of the state or props objects. If the reference values are different, React assumes that the state or props have changed and triggers a re-render. However, if the reference values are the same, React assumes that the state or props have not changed and does not trigger a re-render.

As you have seen in part 1 of this series, the shallow comparison doesn’t check the attributes of states, therefore, React performs to render the entire component. In the next section, we will present some tips to improve performance.

The useMemo and useCallback Hooks are similar. The main difference is that useMemo returns a memoized value and useCallback returns a memoized function.

Using useMemo hook to return a memoized value

Getting back to the introductory project in part 1 of this series, we will create a new branch from the main one and name it caching a branch. We suppose the sum function to make an expensive computation so it should not be always called when rendering the SumComp component. To avoid that issue, we wrap the logic of the sum function into the  userMemo hook as in the following snippet.

const sum = useMemo(() => {
   return expensiveComputing(a, b);
}, [a, b]);

Then, start the app and load the page on our web browser. Check the screenshot below for your reference.

Understanding React Rendering: Part 2 - Using useMemo hook to improve performance
Understanding React Rendering: Part 2 – Using useMemo hook to improve performance

Analysis of the log messages

When loading the page fully first, the expensive function is called once. Then, we clicked the Click here to change text and color twice but the expensive function wasn’t invoked. React only called and rendered the corresponding elements, e.g., the colour and text of the first paragraph tag. Similarly, when clicking on any of the Increment buttons, React also doesn’t call the function to random colour and text.

Using useCallback hook to return a memoized function

If useMemo hook returns a memoized value, useCallback hook returns a memoized function. To help you ease the reading flow, let’s get back to the project as described in the previous section and work out the following example:

import React, {useState, useCallback} from 'react';

function ChildComponent({onClick}) {
    console.log('ChildComponent is rendered');
    return (
        <button onClick={onClick}>Click me</button>
    );
}

function AnotherSumComp() {
    const [count, setCount] = useState(0);
    const [txt, setTxt] = useState("Some text…");
    const incrementCount = useCallback(() => {
        console.log("Calling an expensive computing...");
        setCount(prevCount => prevCount + 1);
    }, [setCount]);
    return (
        <div>
            <p>Text: {txt}</p>
            <p>Count: {count}</p>
            <button onClick={() => {
                console.log("Setting a new text...");
                const text = Math.random().toString(36).slice(2, 7);
                setTxt(text);
            }}>Set Text</button>
            {/*<button onClick={() => { setCount(count + 1); }}>Increment</button>*/}
            <button onClick={() => { incrementCount(); }}>Increment</button>
            <ChildComponent onClick={incrementCount}/>
        </div>
    );
}

export default AnotherSumComp;

In the App component, replace <SumComp/> with <AnotherSumComp/>. Start the app and open the console log of your browser. The output will look like in the following screenshot.

Understanding React Rendering: Part 2 - Using useCallback hook to improve performance
Understanding React Rendering: Part 2 – Using useCallback hook to improve performance

Analysis of the log messages

When the page is fully loaded, only one message is logged because it comes from the child component. The next step is to click on the buttons to see how React renders the components.

Understanding React Rendering: Part 2 - Using useCallback hook to improve performance
Understanding React Rendering: Part 2 – Using useCallback hook to improve performance

Click on the Set Text button

Clicking on this button twice, React renders the entire component twice but only the text is updated.

Click on the button either Increment or Click me

Clicking on these buttons, React also renders the entire component but only the child component is updated and the expensive function is called to compute the output.

Key Takeaways

In this part, we presented how to use useMemo and useCallback to avoid the issue of rendering everything in React. The useMemo hook returns a memorized value while the useCallback hook as its name returns a memorized function. For the sake of finality, feel free to clone and work out the source code published at https://github.com/ITersDesktop/react-caching in the caching branch.

References

[1] React, https://react.dev/, accessed Jan 2nd 2024

[2] Understanding React Re-rendering: An Overview of Shallow Comparison and Optimization with Examples, https://www.linkedin.com/pulse/understanding-react-re-rendering-overview-shallow-examples-pandey/, accessed Jan 2nd 2024

[3] Optimizing Web Apps in React, https://www.turing.com/kb/optimize-web-apps-in-react, accessed Jan 2nd 2024

[4] React useMemo Hook, https://www.w3schools.com/react/react_usememo.asp, accessed Jan 2nd 2014

[5] React useCallback Hook, https://www.w3schools.com/react/react_usecallback.asp, accessed Jan 2nd 2024

[6] Awesome Javascript Interviews, https://github.com/rohan-paul/Awesome-JavaScript-Interviews/tree/master/React/Hooks, accessed Jan 2nd 2024

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.