Performance optimization of React functional components

Optimization ideas

Pinduoduo coupon https://www.fenfaw.net/

There are two main optimization directions:

  1. Reduce the number of rerenders. Because the heaviest (longest) part in React is reconnection (which can be simply understood as diff). If you don't render, there will be no reconnection.
  2. Reduce the amount of calculation. The main purpose is to reduce double calculation. For functional components, each render will execute function calls from scratch.

When using class components, the React optimization API s used are mainly shouldComponentUpdate and PureComponent

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

  1. React.memo
  2. useCallback
  3. useMemo

React.memo

Take an example:

We put a button in the parent component to modify the sub title and introduce Child sub components

You can see that the sub component prints the console for the first time Log ('I am a sub component ')

When you click to modify the subtitle, the Child subcomponent also prints, resulting in unnecessary repeated rendering times

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

import Child from "./Child";
const Index = ()=>{
    const [subTitle, setSubTitle] = useState('I'm 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;


//Sub assembly child js
const Child = ()=>{
    console.log('I'm a subcomponent')
    return (
        <div>I'm a subcomponent</div>
    )
}
export default Child

Optimize it and use react Memo package subassembly

import React from "react";

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

Look again and find that the Child subcomponent does not render repeatedly

useCallback

Here we make another transformation, add an onclick event to the Child sub component, and then click the modify sub title button to find that our Child sub component is re rendered. This is mainly because the handlerClick function re renders when modifying the sub title, resulting in the re rendering of the sub component

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

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

Optimize it, use the handlerClick function of useCallback package processing sub component, click updateSubTitle again to modify the sub title, and find that the Child sub component is not re rendered

// Parent component
const Index = ()=>{
    const [subTitle, setSubTitle] = useState('I'm a subtitle')
    const updateSubTitle = ()=>{
      setSubTitle('Modify subtitle')
    }
    const handlerClick = useCallback(()=>{
      console.log('Sub component 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 dependency as parameters into useCallback, which will return the memoized version of the callback function. This memoizedCallback will be updated only when the dependency changes.

useMemo

useMemo is used to calculate the result cache

Let's take a look at an example, add a calcCount calculation function on the basis of the previous one, and then click updateSubTitle to update the subtitle. It is found that calcCount is recalculated, that is, repeated calculation will be caused for each rendering. If the amount of calculation is large, it will greatly affect the performance

// Parent component
const Index = ()=>{
    const [subTitle, setSubTitle] = useState('I'm a subtitle')
    const updateSubTitle = ()=>{
      setSubTitle('Modify subtitle')
    }
    const handlerClick = useCallback(()=>{
      console.log('Sub component 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. Use useMemo to cache the calculation results. Click updateSubTitle to modify the sub title again. You can find that the calcCount function will not repeat 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 should not be used blindly. It should be used according to specific scenarios. For example, for a large amount of data calculation, it is more applicable. For ordinary worthy calculations, it can not be used, because useMemo itself will consume some performance, and blind use will be counterproductive

Reference reading

  • https://mp.weixin.qq.com/s/YGvmSrr-yhPUNHbwlLSFsA
  • http://www.ptbird.cn/react-hook-useMemo-purerender.html

At the end of the article

Author a Jian Kerry, senior front end engineer, please indicate the source for reprint. If you think this article is helpful to you, remember to praise Sanlian, or scan the code to pay attention to the new front end technology official account of the new official account [front end]. After that, I will send all articles to the public address. In addition, I built a public number that can help our programmers to get rid of the official account. Every week, we push several excellent single little sisters. If you are a programmer and are single, you can follow the code to pay attention to the official account.

Added by resting on Sat, 19 Feb 2022 12:01:37 +0200