Detailed explanation of performance optimization ideas for React functional components

Detailed explanation of performance optimization ideas for React functional components

Optimization ideas

There are two main optimization directions:

  1. Reduce the number of re-renders. Because the heaviest (longest-time-consuming) part in React is reconciliation (which can be simply understood as diff). If you don’t render, there will be no reconciliation.
  2. Reduce the amount of calculation. The main purpose is to reduce repeated calculations. For functional components, each render will execute the function call from the beginning.

When using class components, the React optimization APIs used are mainly: shouldComponentUpdate and PureComponent

So how do we optimize performance in functional components? The following methods are mainly used to optimize

  • React.memo
  • useCallback
  • useMemo

React.memo

Let’s look at an example:

We put a button in the parent component to modify the subtitle and introduce the Child subcomponent

As you can see, the first time the subcomponent comes in, it prints console.log('I am a subcomponent')

When you click to modify the subtitle, the Child component is also printed, resulting in unnecessary repeated rendering times.

//Parent component import {useState} from 'react'

import Child from "./Child";
const Index = ()=>{
    const [subTitle, setSubTitle] = useState('I am a subtitle')
    const updateSubTitle = ()=>{
      setSubTitle('Modify subtitle')
    }
    return (
      <div>
        <div>Functional component performance optimization</div>
        <div>{subTitle}</div>
        <button onClick={updateSubTitle}>Modify subtitle</button>
        <Child/>
      </div>
    );
  }
  
  export default Index;


//Child component Child.js
const Child = ()=>{
    console.log('I am a child component')
    return (
        <div>I am a child component</div>
    )
}
export default Child

Optimize it and use React.memo to wrap the subcomponent

import React from "react";

const Child = ()=>{
    console.log('I am a child component')
    return (
        <div>I am a child component</div>
    )
}
export default React.memo(Child)

Observe again and find that the Child subcomponent is not rendered repeatedly

useCallback

Here we modify it again, add an onclick event to the Child subcomponent, and then click the modify subtitle button, and find that our Child subcomponent is re-rendered. This is mainly because the handlerClick function re-renders the changes when modifying the subtitle, causing the subcomponent to re-render.

// Parent component const Index = ()=>{
    const [subTitle, setSubTitle] = useState('I am a subtitle')
    const updateSubTitle = ()=>{
      setSubTitle('Modify subtitle')
    }
    const handlerClick = ()=>{
      console.log('subcomponent click')
    }
    return (
      <div>
        <div>Functional component performance optimization</div>
        <div>{subTitle}</div>
        <button onClick={updateSubTitle}>Modify subtitle</button>
        <Child onClick={handlerClick}/>
      </div>
    );
  }

//Child subcomponent const Child = (props)=>{
    console.log('I am a child component')
    return (
        <div>
            <div>I am a child component</div>
            <button onClick={props.onClick}>Subcomponent button</button>
        </div>
    )
}
export default React.memo(Child)

To optimize, use useCallback to wrap the handlerClick function of the child component, click updateSubTitle again to modify the subtitle, and find that the Child subcomponent is not re-rendered

// Parent component const Index = ()=>{
    const [subTitle, setSubTitle] = useState('I am a subtitle')
    const updateSubTitle = ()=>{
      setSubTitle('Modify subtitle')
    }
    const handlerClick = useCallback(()=>{
      console.log('subcomponent click')
    },[])

    return (
      <div>
        <div>Functional component performance optimization</div>
        <div>{subTitle}</div>
        <button onClick={updateSubTitle}>Modify subtitle</button>
        <Child onClick={handlerClick}/>
      </div>
    );
  }
  
  export default Index;

Here is the usage of useCallback

const callback = () => {
  doSomething(a, b);
}

const memoizedCallback = useCallback(callback, [a, b])

Pass the function and dependencies as parameters to useCallback, which will return a memoized version of the callback function. This memoizedCallback will only be updated when the dependencies change.

useMemo

useMemo is used to cache calculation results

Let's take a look at an example. We add a calcCount calculation function based on the previous one, and then click updateSubTitle to update the subtitle. We find that calcCount is recalculated, which means that each rendering will cause repeated calculations. If the amount of calculation is large, it will greatly affect the performance.

// Parent component const Index = ()=>{
    const [subTitle, setSubTitle] = useState('I am a subtitle')
    const updateSubTitle = ()=>{
      setSubTitle('Modify subtitle')
    }
    const handlerClick = useCallback(()=>{
      console.log('subcomponent click')
    },[])

    const calcCount = ()=>{
      
      let totalCount = 0
      for(let i=0;i<10000;i++){
        totalCount+=i
      }
      console.log('totalCount',totalCount)
      return totalCount
    }

    const count = calcCount()

    return (
      <div>
        <div>Functional component performance optimization</div>
        <div>{subTitle}</div>
        <button onClick={updateSubTitle}>Modify subtitle</button>
        <div>count:{count}</div>
        <Child onClick={handlerClick}/>
      </div>
    );
  }

Optimize it and use useMemo to cache the calculation results. Click the updateSubTitle button again to modify the subtitle. You can find that the calcCount function no longer repeats the calculation.

 const calcCount = ()=>{
      
      let totalCount = 0
      for(let i=0;i<10000;i++){
        totalCount+=i
      }
      console.log('totalCount',totalCount)
      return totalCount
    }

    const count = useMemo(calcCount,[])

Finally, it should be noted that useMemo cannot be used blindly. It should be used according to specific scenarios. For example, if the amount of data calculation is relatively large, then it is more applicable. For some ordinary calculations that are worth calculating, it can be ignored, because useMemo itself will also consume some performance. Blind use will be counterproductive.

References

https://mp.weixin.qq.com/s/YGvmSrr-yhPUNHbwlLSFsA

http://www.ptbird.cn/react-hook-useMemo-purerender.html

This is the end of this article about performance optimization of React functional components. For more relevant React performance optimization content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • How to add typescript type hints to react component library
  • In-depth understanding of react component types and usage scenarios
  • React's implementation method of passing class names to child components through parent components
  • Do you know the difference between React functional components and class components?

<<:  MySql 5.7.20 installation and configuration of data and my.ini files

>>:  Forever+nginx deployment method example of Node site

Recommend

Detailed steps to install Docker mongoDB 4.2.1 and collect springboot logs

1: Install mongodb in docker Step 1: Install mong...

Example code of Vue3 encapsulated magnifying glass component

Table of contents Component Infrastructure Purpos...

Understanding and usage scenarios of ES6 extension operators

Table of contents 1. Replace the apply method, ge...

Vue + element to dynamically display background data to options

need: Implement dynamic display of option values ...

Reasons and solutions for not being able to detect array changes in Vue2

Table of contents Workaround Why can't I moni...

MySQL 5.7.27 winx64 installation and configuration method graphic tutorial

This article shares the installation and configur...

Solve the problem that Docker pulls MySQL image too slowly

After half an hour of trying to pull the MySQL im...

MySQL 8.0.21 installation tutorial with pictures and text

1. Download the download link Click download. You...

JavaScript to add and delete messages on the message board

This article shares a small example of adding and...

An article to help you understand the basics of VUE

Table of contents What is VUE Core plugins in Vue...

Solution to Linux CentOS 6.5 ifconfig cannot query IP

Recently, some friends said that after installing...

What are the advantages of MySQL MGR?

MGR (MySQL Group Replication) is a new feature ad...

Solution to the problem that the mysql8.0.11 client cannot log in

This article shares with you the solution to the ...