background

UseCallback and useMemo are used to cache functions and objects in React. However, performance optimization also has a cost. Excessive cache will occupy too much memory, and the garbage collector will not release it in time, resulting in negative optimization. Therefore, it should not be used in most cases.

When to use

1. The child component uses useEffect and relies on the props passed in by the parent component

Look at the following example

/ / child component
function Foo({bar, baz}) {
  React.useEffect(() = > {
    const options = {bar, baz}
    buzz(options)
  }, [bar, baz]) 
  
  return <div>foobar</div>
}

/ / the parent component
function Blub() {
  const bar = () = > {}
  const baz = [1.2.3]
  return <Foo bar={bar} baz={baz} />
}
Copy the code

The child Foo uses useEffect and relies on the parameters bar and baz passed by the parent Blub. In this case, useEffect is called whenever the parent updates, even though the parameter value has not changed because the reference has changed. So how to solve this problem? Look at the code below.

/ / child component
function Foo({bar, baz}) {
  React.useEffect(() = > {
    const options = {bar, baz}
    buzz(options)
  }, [bar, baz])
  return <div>foobar</div>
}

/ / the parent component
function Blub() {
  const bar = React.useCallback(() = > {}, [])
  const baz = React.useMemo(() = > [1.2.3], [])
  return <Foo bar={bar} baz={baz} />
}
Copy the code

UseCallback and useMemo are introduced in the parent component to wrap the parameters passed to the child component, so that useEffect dependent parameters are not called multiple times even if the parent component is updated.

2. The child component uses React. Memo

Look at the following example

/ / child component
const CountButton = React.memo(function CountButton({onClick, count}) {
  return <button onClick={onClick}>{count}</button>
})

/ / the parent component
function DualCounter() {
  const [count1, setCount1] = React.useState(0)
  const increment1 = () = > setCount1(c= > c + 1)

  const [count2, setCount2] = React.useState(0)
  const increment2 = () = > setCount2(c= > c + 1)

  return (
    <>
      <CountButton count={count1} onClick={increment1} />
      <CountButton count={count2} onClick={increment2} />
    </>)}Copy the code

The react. memo is used for the child component. The parent component is updated and the child component is not updated to optimize performance without changing the props. However, in this case, as long as the parent component is updated, the child component will be updated twice. The reason is that the child component uses the function of the parent component, and the parent component update function will be updated. Since the memo is a shallow comparison, the child component will be updated when the function updates, so the performance optimization effect cannot be achieved. The solution is as follows

/ / child component
const CountButton = React.memo(function CountButton({onClick, count}) {
  return <button onClick={onClick}>{count}</button>
})

/ / the parent component
function DualCounter() {
  const [count1, setCount1] = React.useState(0)
  const increment1 = React.useCallback(() = > setCount1(c= > c + 1), [])

  const [count2, setCount2] = React.useState(0)
  const increment2 = React.useCallback(() = > setCount2(c= > c + 1), [])

  return (
    <>
      <CountButton count={count1} onClick={increment1} />
      <CountButton count={count2} onClick={increment2} />
    </>)}Copy the code

The parent component uses useCallback to wrap the function, so that the parent component keeps the reference of the function unchanged during the update, so that the child component does not update, thus achieving performance optimization. If the argument is an object, use useMemo.

3. Components that use expensive computing

Take a look at the following code

function RenderPrimes({iterations, multiplier}) {
  const primes = calculatePrimes(iterations, multiplier)
  return <div>Primes! {primes}</div>
}

Copy the code

Assume that calculatePrimes is a complex function that takes a long time to compute and return results, in which case it is necessary to use useMemo to optimize the component. The modified code is as follows

function RenderPrimes({iterations, multiplier}) {
  const primes = React.useMemo(() => calculatePrimes(iterations, multiplier), [
    iterations,
    multiplier,
  ])
  return <div>Primes! {primes}</div>
}
Copy the code

If the calculated results are the same every time, then calculatePrimes will not be called every time to do complex calculations, and only the results of the last calculation will be used.

conclusion

The above are the three situations I have sorted out using useCallback and useMemo. If there are any other scenarios, please add them.

Refer to the article

Jancat. Making. IO/post / 2019 / t…