DEV Community

Peter Yuan
Peter Yuan

Posted on

useCallback VS useMemo

We all know how to use React.useCallback and React.useMemo, but sometimes we will be confused about which one we should choose.

Here I will show you guys some cases to help you understand what hook function we should use in some specific situations.

import React, { useState } from 'react'

export default function App() {
  const [num1, setNum1] = useState(10)
  const [num2, setNum2] = useState(12)

  return <div>{num1 + num2}</div>
}
Enter fullscreen mode Exit fullscreen mode

In the above simple example case, we can just get the sum by num1 + num2 in the HTML element part, but if we have some more complex calculation logic, we shouldn't do that anymore.

import React, { useState, useMemo } from 'react'

export default function App() {
  const [num1, setNum1] = useState(10)
  const [num2, setNum2] = useState(12)

  const sum = useMemo(() => {
    const _num1 = Number(num1),
      _num2 = Number(num2)
    if (Number.isNaN(_num1) || Number.isNaN(_num2)) {
      return "check your num's type"
    }
    return _num1 + _num2
  }, [num1, num2])

  return <div>{sum}</div>
}

Enter fullscreen mode Exit fullscreen mode

In this example code block, we chose useMemo to keep the result value of num1 + num2, but we add some type check logic, because we can't totally trust the num1 or num2's type would be number, so when the type goes wrong, we will show the placeholder text.

In this situation, you can't realize this effect in the HTML part with simple code in one line. Of course, you can write some logic code in the HTML part with conditional operators (JSX allow you to do that), but the cost is sacrificing the readability of the code.

So, useMemo is a good choice to handle this case.

Ok, let's go on one more complex case.

import React, { useState, useMemo } from 'react'

export default function App() {
  const [num1, setNum1] = useState(10)
  const [num2, setNum2] = useState(12)
  const [num3, setNum3] = useState(100)
  const [num4, setNum4] = useState(120)

  const sum1 = useMemo(() => {
    const _num1 = Number(num1),
      _num2 = Number(num2)
    if (Number.isNaN(_num1) || Number.isNaN(_num2)) {
      return "check your num's type"
    }
    return _num1 + _num2
  }, [num1, num2])

  return (
    <>
      <div>{sum1}</div>
      <div>{num3 + num4}</div>
    </>
  )
}

Enter fullscreen mode Exit fullscreen mode

As you can see, we have num3 and num4 here to render the sum of them. If we also want to reuse the logic of num1 + num2, what should we do? Of course we can still use useMemo to define one sum2, but it's not a good idea to reuse the logic to validate the num's type. So we need split the validate logic out from the useMemo. Then useCallback shows up!

import React, { useState, useCallback } from 'react'

const validteNumAndSum = (number1, number2) => {
  const _num1 = Number(number1),
    _num2 = Number(number2)
  if (Number.isNaN(_num1) || Number.isNaN(_num2)) {
    return "check your num's type"
  }
  return _num1 + _num2
}

export default function App() {
  const [num1, setNum1] = useState(10)
  const [num2, setNum2] = useState(12)
  const [num3, setNum3] = useState(100)
  const [num4, setNum4] = useState(120)

  const sumFunc = useCallback(validteNumAndSum, [])

  return (
    <>
      <div>{sumFunc(num1, num2)}</div>
      <div>{sumFunc(num3, num4)}</div>
    </>
  )
}

Enter fullscreen mode Exit fullscreen mode

As you can see, we use useCallback to return a new function with the logic of validating num's type and calculating the sum, and we reuse this validteNumAndSum function in the HTML part easily.

Ok, let's go to the conclusion part:

If you can easily make a calculation (math or more complex situation), you don't need both of them useMemo and useCallback.

If your calculation logic is complex and just needs to be calculated once only, you can pick the useMemo hook to package your calculation process and return one simple result.

But if you would use the same logic more than one time, you can choose useCallback to return a memorized function to reuse it in your component.


I am so sorry about useCallback case. I made a mistake that is to explain when to choose useCallback and created a bad example case.

Here I will try again.

import React, { useState, useCallback } from 'react'

export default function App() {
  const [base, setBase] = useState(0)
  const [num1, setNum1] = useState(10)
  const [num2, setNum2] = useState(12)
  const [num3, setNum3] = useState(100)
  const [num4, setNum4] = useState(120)

  const sumFunc = useCallback(
    (number1, number2) => {
      const _num1 = Number(number1),
        _num2 = Number(number2)
      if (Number.isNaN(_num1) || Number.isNaN(_num2)) {
        return "check your num's type"
      }
      return _num1 + _num2 + base
    },
    [base],
  )

  return (
    <>
      <input
        type="number"
        value={base}
        onChange={e => {
          setBase(Number(e.target.value))
        }}
      />
      <div>{sumFunc(num1, num2)}</div>
      <div>{sumFunc(num3, num4)}</div>
    </>
  )
}

Enter fullscreen mode Exit fullscreen mode

In the code above, we add one base number as another variable data, and every sum should be added with the base value, and we have an input to change the value of base, so every time base is changed and sumFunc would be modified too, and we can use it to calculate the right result.

So I will update my conclusion about useCallback: if we just need to reuse some logic, we can package this logic into a function and even split it out from the component as a util function to reuse it anywhere. And if our logic still relies on some variable of the component, we can use useCallback to package the logic and return a memorized new function.

Top comments (0)