How to optimize react rendering
Tags: javascript, react, webdev
Published: 2022-10-05 23:14:01






React is the one of the most used framework in terms of Javascript. Some developer may use it without knowing how to optimize rendering.
I believe this article is going to help those people！



## React Rendering 
Any screen update in a React app happens in three steps:
- Trigger
- Render
- Commit 

We have to understand what is going to trigger render and distinguish Render and Commit.
In following, "render" should be recognized as "Render step" of React.


### What does trigger component rendering ?
- state change
- parent component's rendering

 As default behavior of React, when parent component is getting rendered, all child components inside is getting rendered.　
 (Not necessarily changes made to the DOM. Diff is caluculate though! )
- props change

### What rendering does
calculate which of their properties have changed since the previous render.

### What commit does
apply minimal necessary operations(calculate while rendering) to make the DOM match the rendering output

## Optimize rendering
We don't have to think render is bad thing because it is the opportunity that React knows whether commit is needed or not.
But it is good to optimize rendering!

Let's say we are creating the component called ParentComponent which holds the ShowScore Component as child component.
Parent Component has two states to store score and has two function just call setState function and increment the state.
This component receive theme as props to change className.

```js

    function ParentComponent({theme}){
        const [scoreA,setScoreA] = useState(0);
        const [scoreB,setScoreB] = useState(0);

        const changeScoreA =()=>{
            setScoreA(prev => prev + 1);
        }

        const changeScoreB =()=>{
            setScoreB(prev => prev + 1);
        }
       
      
        return (
            <div className={theme}>
            <ShowScore who={"A"} score={scoreA} changeFn={changeScoreA} />
            <ShowScore who={"B"} score={scoreB} changeFn={changeScoreB} />
            </div>
           
        )
    }

```

In ShowScore component, we received score, who, and changeFn as props.
 we use useEffect to check the component is rendered.
```js
    function ShowScore({score,who,changeFn}){
        useEffect(()=>{
           console.log(`renderd: ${who} with ${score}`)
        })

        return (
            <>
                <p>{who} - {score}</p>
                <button onClick={changeFn}>change</button>
            </>
           
        )
    }
```



Let's see what happens when we change the theme which is passed to ParentComponent.

As I mentioned above, React re-render a component when props is changed.
And when parent component is rendered, child component inside is also rendered.

With theme changed, ParentComponent is re-rendered and ShowComponent is also re-rendered even though props passed to ShowScore is not changed.


![change-theme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ho9sci781jxdb3zis6gb.gif)


We don't have to re-render, right?


In such case, we can use React.memo. This allow us to prevent re-render unless props is changed.

Let's wrap ShowScore component with React.memo.

```js
  const ShowScore = memo(function ShowScore({score,who,changeFn}){
        //...
    })  
```


![change-theme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ho9sci781jxdb3zis6gb.gif)

Same things happened!! It is not suppose to be re-rendered because props passed to ShowScore is not changed.
Why did this happen ?

The answer is that functions defined within the component will re-defined when component is re-rendered and the reference of function will change.\
The function is no longer same even though content inside the function is same！

To solve this problem, we can use useCallback hook. This allows us to cache the function between renders.

Let's wrap the function with useCallback!

```js
     function ParentComponent({theme}){
        //...
        const changeScoreA =useCallback(()=>{
                setScoreA(prev => prev + 1);
            },[])
        const changeScoreB =useCallback(()=>{
            setScoreB(prev => prev + 1);
        },[])
        //...
     }
```

We have to pass the dependency array as second parameter of useCallback hook. Only when the dependency is changed, function is re-created.\
In this case, we can use empty dependency array because we don't have the variable which changes function's content.

Now that we warped function with useCallback, ShowScore component is not re-rendered when we change theme!


![useCallback](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ydyuxizb5ih5ysxkyq7.gif)


Next, let's click the change button. Before that, let's add another function to ParentComponent

```js

 function ParentComponent({theme}){
    //...
        const  isPassed = ()=>{
                while(i < 1000000) i++;
                return scoreA > 2
            }
        }
     return (
            <div className={theme}>
            <ShowScore who={"A"} score={scoreA} changeFn={changeScoreA} />
            <span>{isPassed() && "passed"}</span> // this line is also added 
            <ShowScore who={"B"} score={scoreB} changeFn={changeScoreB} />
            </div>
           
        )

```

It's kind of strange, but let's say we check only scoreA and if it is more than 2, show "passed". 
And we create isPassed function and make it taking long time to see what happens.





![isPassed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7yjgadpo8rmqscce6kmy.gif)

Once we click the change button next to A label, score is changing with taking a lot of time.
The same can be said for B even though we don't have to check B's score.

In this case, we can use useMemo hook. This allows us  cache the result of a calculation between re-renders.

Let's use useMemo.

```js
function ParentComponent({theme}){
    //...
    const  isPassed = useMemo(()=>{
        let i =0;
        while(i < 1000000000) i++;
        if(scoreA >= 2 ) return true
       },[scoreA])

        return (
            <div className={theme}>
            <ShowScore who={"A"} score={scoreA} changeFn={changeScoreA} />
            <span>{isPassed && "passed"}</span> // removed ()
            <ShowScore who={"B"} score={scoreB} changeFn={changeScoreB} />
            </div>
        )
```
We have to pass the dependency array to the useMemo function as second argument same as useCallback function.
In this case,  we can pass scoreA as dependency and only when scoreA is changed, callback function is executed and returns value.

Let's see what happened with useMemo! 

![useMemo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d0mwizoeq7feh6521rma.gif)

As soon as change button next to B is clicked, score is incremented!


you can check out my code [here](https://replit.com/@Syuya/DigitalThunderousDisc#src/ParentComponent.jsx)!




## Reference
- [react doc - beta](https://beta.reactjs.org/)
- [Codevolution](https://www.youtube.com/c/Codevolution/playlists)
- [Reactのレンダリングに関する完全ガイド](https://qiita.com/hellokenta/items/6b795501a0a8921bb6b5)