DEV Community

Cover image for Day 56 of #100DaysOfCode: Avoid useless re-rendering with React.memo for the customized hooks
Jen-Hsuan Hsieh
Jen-Hsuan Hsieh

Posted on

Day 56 of #100DaysOfCode: Avoid useless re-rendering with React.memo for the customized hooks

1. Introduction

I create a React hook recently which is called use-react-monitor. It can help us to monitor endpoints for the specified interval and reset the interval when it changes.

  • We have to install the package in the first step
npm install use-react-monitor -S
Enter fullscreen mode Exit fullscreen mode
  • We can use the hook for endpoints that we want to monitor to
import React from 'react';
import useMonitor from 'use-react-monitor';

const Tester = () => {
    const interval = 3000;
    const {results, status, lastTimes} = useMonitor(
        { urls:['http://rem-rest-api.herokuapp.com/api/users',
                'http://rem-rest-api.herokuapp.com/api/users'],
          freshRate: interval});

    return (
        <>
            {<Results results = {results} status = {status}/>}
        </>
    )
}

const Results = ({ results, status}) => {
    const refCount = React.useRef(0);
    refCount.current++;
    return (
        <div>
        <p>
       {`render time: ${refCount.current}`}
        </p>
        {results && results.map((result, i) =>{
            return (
                <>
                    <div key={`status-${i}`}>Status: {status && status[i]}</div>
                    <ul key={i}>
                        {result.data.map((r, index) => {
                            return (<li key={index}>{r.id} {r.firstName} {r.lastName}</li>)
                        })}
                    </ul>
                </>)
        })}
     </div>
    );
};

export default Tester
Enter fullscreen mode Exit fullscreen mode
  • Then it can polling to fetch the resources from endpoints. Now we add useRef to check if the child was re-rendered even though the fetched result was unchanged.
const Results = ({ results, status}) => {
    const refCount = React.useRef(0);
    refCount.current++;
    return (
        <div>
        <p>
       {`render time: ${refCount.current}`}
        </p>
        ...
    )
};
Enter fullscreen mode Exit fullscreen mode
  • We found that the child component was re-rendered whenever use-react-monitor return the value. However, what we expect is that the child component was re-rendered only when use-react-monitor return new values.

Alt Text

2. Avoid useless re-rendering with React.memo

React.memo is a HOC. We can pass our child component with the compare function and React.memo will perform shallow comparing.
The wrapped child component will only be re-rendered when use-react-monitor return new values.

Compare function

function monitoredPropsAreEqual(prevResults, nextResults){
    return JSON.stringify(prevResults) === JSON.stringify(nextResults);
}
Enter fullscreen mode Exit fullscreen mode

Wrap the child component with React.memo

import React, {memo} from 'react';
const Tester = () => {
    const interval = 3000;
    const {results, status, lastTimes} = useMonitor(
        { urls:['http://rem-rest-api.herokuapp.com/api/users',
                'http://rem-rest-api.herokuapp.com/api/users'],
          freshRate: interval});

    return (
        <>
            {<MemorizedResults results = {results} status = {status}/>}
        </>
    )
}
const MemorizedResults = memo(Results, monitoredPropsAreEqual);
Enter fullscreen mode Exit fullscreen mode

Result

Alt Text

That's it!

Side projects

There are some of my articles. Feel free to check if you like!

References

Discussion (0)