origin

We often have a scenario where a parent component’s state changes and needs to be rerendered, usually along with all of its children.

When we pass a subcomponent props that doesn’t change, the subcomponent doesn’t need re-render

In the previous class component, we could use PureComponent or shouldComponentUpdate to control whether or not a subcomponent needs to render. Therefore, memo, useMemo, and useCallback were created to optimize the performance of the component rendering for handling functions

React.memo

The memo only checks changes to props. By default, the memo only compares complex objects at a superficial level. If you want to control the comparison process, pass in a second argument to your custom comparison function.

Note: However, there is a useStateuseReducer or useContext Hook in the function, which will still re-render when state or context changes

import { ChangeEvent, memo,useState } from "react" interface IProps{ count? :number value? :string} const Child=(props:IProps):any=>{console.log(' subcomponent render'); Return (<div> subcomponent count:{props. Count}</div>)}; Const ChildMemo=memo(Child) // ChildMemo=memo(Child) // ChildMemo=memo(Child) // const ChildMemo=memo(Child,(prevProps,) nextProps)=>{ // if(prevProps.count===1){ // return true // }else { // return false // } // }) const Home =() =>{ const [count, setCount] = useState(0) const [value, setValue] = useState('null'); const addClick= () =>{ setCount(count + 1) } const handleChange=(e: ChangeEvent<HTMLInputElement>)=>{setValue(e.target.value)} console.log(' parent component render') return (<div> <p> parent component {count}) times</p> <button onClick={addClick}>Click me</button> <input onChange={(e) => handleChange(e)} /> <ChildMemo count={count}></ChildMemo> </div> ); }Copy the code

Do not useReact.memoWhen value changes, the child component is still re-rendered, whereas the child component does not need to be rendered if it does not depend on valueAnd then let’s look at plusReact.memo

Parent component changing value does not affect child component re-render when wememoPrevProps. Count ===1 returns true. If parent count does not equal 1, child re-render will not be performed

UseMemo and useCallback

If useMemo returns a function, use useCallback to omit the top-level function. UseCallback is a variant of useMemo. Both hooks return cached values. UseMemo returns cached variables, useCallback returns cached functions

import { ChangeEvent, memo,useMemo,useState } from "react" interface IProps{ onButtonClick? :()=>void, count? :number value? :string} const Child=(props:IProps):any=>{console.log(' subcomponent render'); Return (<div> subcomponent count:{props. Count}</div>)}; const ChildMemo=memo(Child) const Home =() =>{ const [count, setCount] = useState(0) const [value, setValue] = useState('null'); const addClick= () =>{ setCount(count + 1) } const handleChange=(e: ChangeEvent<HTMLInputElement>)=>{setValue(e.target.value)} /** Not useMemo */ const childMemo =(()=>{let result = Math.random() * count; console.log('render-result') return result; })() /** useMemo*/ / const childMemo =useMemo(()=>{// let result = math.random () * count; // console.log('render-result') // return result; //},[count]) console.log(' parent component render') return (<div> <p> parent component {count} times <br/> Use useMemo count {childmemo}</p> <button  onClick={addClick}>Click me</button> <input onChange={(e) => handleChange(e)} /> <ChildMemo count={count}></ChildMemo> </div> ); }Copy the code

If we do not use useMemo, we can see that childMemo changes the value field as well. However, childMemo relies on count and should not change

When we useuseMemoYou can see that log changes only if count changes, and this is analogous to computed in VUE

UseCallback is an extension of useMemo, and remember that useMemo returns cached variables, and useCallback returns cached functions so let’s change that if childMemo returns a function

     const childmemo=useMemo(()=>{
        return ()=>{
            let result = Math.random() * count;
            console.log('render-result')
            return result;
        }
    },[count])
Copy the code

At this point, there will be useMemo does not work, at this point we can use useCallback modification, omit the upper function, rewrite

import { ChangeEvent, memo,useCallback,useEffect,useLayoutEffect,useMemo,useRef,useState } from "react" interface IProps{ callback? :()=>number, count? :number|undefined value? :string} const Child=(props:IProps):any=>{console.log(' subcomponent render'); Let the value: number | undefined useEffect = 0 (() = > {value = props. The callback && props. The callback () the console. The log (' callback updated, value); },[props. Callback]) return (<div> subcomponent count:{props. Count} </div>)}; const ChildMemo=memo(Child) const Home =() =>{ const [count, setCount] = useState(0) const [value, setValue] = useState('null'); const addClick= () =>{ setCount(count + 1) } const handleChange=(e: ChangeEvent<HTMLInputElement>)=>{ setValue(e.target.value) } const childmemo=useCallback(()=>{ console.log('render-result') let result = Math.random() * count; Return result},[count]) console.log(' parent component render') return (<div> <p> parent component {count} times</p> <button onClick={addClick}>Click me</button> <input onChange={(e) => handleChange(e)} /> <ChildMemo count={count} callback={childmemo}></ChildMemo> </div> ); }Copy the code

Callback is triggered when count is changed. If useCallback is removed and value is modified, childMemo is also executed.

The above is a process of personal record understanding, if there are any questions please correct ~