Note: hooks can only be used in functions (stateless components)

Use the same syntax for useMome, useCallback. Both hooks return cached values, useMemo returns cached variables, useCallback returns cached functions.

const value = useMemo(fnM, [a]);

const fnA = useCallback(fnB, [a]);
Copy the code

1, The application of memo

React.memo is a higher-order component. It is very similar to the React.PureComponent.

By default, only shallow comparisons are performed on complex objects. If you want to control the comparison process, pass in your custom comparison function as a second argument. This is the opposite of the return value of the shouldComponentUpdate method.

Function MyComponent(props) {/* use props */} function areEqual(prevProps, NextProps) {/* Return true if the return from passing nextProps to render is the same as the return from passing prevProps to render, Export default react. memo(MyComponent, areEqual);Copy the code

When a parent component introduces a child component, there is often some unnecessary waste between components. Let’s take a look at this scenario through examples

Const Child = (props) => {console.log(' Child? ') return(<div> I am a child component </div>); } const Page = (props) => { const [count, setCount] = useState(0); Return (< > < button onClick = {(e) = > {setCount (count + 1)}} > 1 < / button > < p > count: {count} < / p > < Child / > < / a >)}Copy the code

Each time the parent component updates count, the child component updates. The following version uses memo, and the count change subcomponent is not updated

Const Child = (props) => {console.log(' Child? ') return(<div> I am a child component </div>); } const ChildMemo = memo(Child); const Page = (props) => { const [count, setCount] = useState(0); Return (< > < button onClick = {(e) = > {setCount (count + 1)}} > 1 < / button > < p > count: {count} < / p > < ChildMemo / > < / a >)}Copy the code

2. Use useCallback

The memo does not seem to be working when the parent passes state to the child, so we need to introduce hooks useCallback and useMemo.

Interface ChildProps {name: string; onClick: Function; } const Child = ({name, onClick}: ChildProps): jsx.Element => {console.log(' Child? ') return(<> <div> I am a child component, and the parent sends the data: {name}</div> <button onClick={onclick. bind(null, 'new subcomponent name')}> Change name</button> </>); } const ChildMemo = memo(Child); const Page = (props) => { const [count, setCount] = useState(0); Const [name, setName] = useState('Child component '); Return (<> <button onClick={(e) => {setCount(count+1)}}> add 1</button> <p>count:{count}</p> <ChildMemo name={name} onClick={(newName: string) => setName(newName)}/> </> ) }Copy the code

When the parent calls the child, add useCallback to the onClick parameter [], and it will not change after the first initialization.

Interface ChildProps {name: string; onClick: Function; } const Child = ({name, onClick}: ChildProps): jsx.Element => {console.log(' Child? ') return(<> <div> I am a child component, and the parent sends the data: {name}</div> <button onClick={onclick. bind(null, 'new subcomponent name')}> Change name</button> </>); } const ChildMemo = memo(Child); const Page = (props) => { const [count, setCount] = useState(0); Const [name, setName] = useState('Child component '); Return (<> <button onClick={(e) => {setCount(count+1)}}> add 1</button> <p>count:{count}</p> <ChildMemo name={name} onClick={ useCallback((newName: string) => setName(newName), []) }/> {/* useCallback((newName: String) => setName(newName),[]) */} {/* This uses useCallback to optimize the function passed to the child component, only initialize this function once, no new function is generated next time </>)}Copy the code

3. Use useMemo

Interface ChildProps {name: {name: string; color: string }; onClick: Function; } const Child = ({name, onClick}: ChildProps): jsx.Element => {console.log(' Child? ') return( <> <div style={{ color: Name. Color}}> I am a child of the component, the parent of the data: {name}</div> <button onClick={onclick. bind(null, 'new subcomponent name')}> Change name</button> </>); } const ChildMemo = memo(Child); const Page = (props) => { const [count, setCount] = useState(0); Const [name, setName] = useState('Child component '); Return (< > < button onClick = {(e) = > {setCount (count + 1)}} > 1 < / button > < p > count: {count} < / p > < ChildMemo name = {{name, color: name.indexOf('name') ! = = 1? 'red' : 'green'}} onClick={ useCallback((newName: string) => setName(newName), []) } /> </> ) }Copy the code

Update attribute name is the object type, then the child component is still the same execution, when the parent component updates other states, the child component’s name object property will always be re-rendering changes, resulting in constant execution, which is also an unnecessary waste of performance.

To solve this problem, use the name parameter to use useMemo, depending on changes in the state.name data

interface ChildProps { name: { name: string; color: string }; onClick: Function; } const Child = ({name, onClick}: ChildProps): jsx.Element => {console.log(' Child? ') return( <> <div style={{ color: Name. Color}}> I am a child of the component, the parent of the data: {name}</div> <button onClick={onclick. bind(null, 'new subcomponent name')}> Change name</button> </>); } const ChildMemo = memo(Child); const Page = (props) => { const [count, setCount] = useState(0); Const [name, setName] = useState('Child component '); Return (<> <button onClick={(e) => {setCount(count+1)}}> +1 </button> <p>count:{count}</p> <ChildMemo // use useMemo. Name ={useMemo(()=>({name, color: name.indexof ('name')! = = 1? 'red' : 'green' }), [name]) } onClick={ useCallback((newName: string) => setName(newName), []) } {/* useCallback((newName: String) => setName(newName),[]) */} {/* This uses useCallback to optimize the function passed to the child component, only initialize this function once, no new function is generated next time /> </>)}Copy the code

4, summarize

In cases where the child component does not need the values and functions of the parent component, you simply wrap the child component with the Memo function. In the case of functions, you need to consider whether any function is passed to the child component using useCallback. Use useMemo when values are dependent on items that are equivalent to objects and arrays (do not use useMemo when returning primitive data types such as strings, numbers, and Booleans). Don’t blindly use these hooks.

Reference links:

React Hook Best practices

React.memo

UseCallback +useMemo+ Memo performance optimizations