How to use React useMemo and useCallback hook

Is it bad to re-initialize local variables, and event functions inside a React functional component?


// Reinitialize variables and functions on every state update
function App() {

  const [value, changeValue] = React.useState('');

  const [cats, updateCatList] = React.useState([{name: 'Mr. Whiskers'}, {name: 'Fluffy'}]);

  const handleSubmit = () => {
    // ... some logic and print list
    updateCatList([...cats, value]);
  };

  const handleChange = e => {
    // ... Some logic and update state
    changeValue(e.target.value);
  };

  return (
    <>
      <input onChange={handleChange} />
      <button onClick={handleSubmit}>Submit</button>
      {JSON.stringify(cats)}
    </>
  );
}

99% of time, probably not.

But maybe, you’re that 1% that you notice some heavy computation is killing your apps performance.

Or maybe, you just want to pre-optimize.

If those are the cases, let me tell you about why React useMemo, and useCallback is useful for your problems, and how it works.

Why React useMemo is useful

This hook creates a memoized value.

Sometimes you have to compute a value through a complex calculation or you have to make a call to a costly database network.

Using React useMemo will perform the action once, and store the value as a memoized value.

So the next time you reference that local variable, it will get the value quicker.


useMemo(() => callback, array_dep);

Here’s how to use React useMemo:


const catsValue = React.useMemo(() => highlyCostCatQueryCall());

This hook behaves almost like React useEffect. In the sense that if you don’t pass an empty array ([]) as the second parameter, React useMemo will get triggered on any update.


const catsValue = React.useMemo(() => highlyCostCatQueryCall(), []);

If you’d like to trigger this hook again, add some dependencies in that empty array.


const catsValue = React.useMemo(() => highlyCostCatQueryCall(arg1, arg2), [arg1, arg2]);

If any of those dependencies in the array change in value, then React useMemo will re-trigger, and save the new value as a memoized value.

Why React useCallback is useful

React useCallback is similar to useMemo.

The difference between useCallback and useMemo is that useCallback returns a memoized callback function. And useMemo returns a memoized value

The objective is to not re-initialize the function or the value, unless it’s array dependencies have changed.


useCallback(func, array_dep);

Here’s how to use React useCallback:


function App() {
  const [counter, setCounter] = React.useState(0);
  const [autoCounter, setAutoCounter] = React.useState(0);

  const incrementCallback = React.useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  React.useEffect(() => {
    setInterval(() => {
      setAutoCounter(c => c + 1);
    }, 1000);
  }, []);

  return (
    <>
      <h1>Auto counter: {autoCounter}</h1>
      <h2>Manual counter: {counter}</h2>
      <button onClick={incrementCallback}>Increment</button>
    </>
  );
}

In the example above I have 2 different useState variables, counter and autoCounter.

autoCounter will auto increment every second by 1.

I set that code command inside a setInterval() within my React useEffect hook.


const [autoCounter, setAutoCounter] = React.useState(0);

React.useEffect(() => {
  setInterval(() => {
    setAutoCounter(c => c + 1);
  }, 1000);
}, []);

In the example above I also have another React state variable called counter.

This variable will need to get incremented manually by clicking on the button.

Here’s the click event handler for the button:


const incrementCallback = React.useCallback(() => {
  setCounter(counter + 1);
}, [counter]);

Notice how I wrap my callback function inside a React useCallback hook.

That lets React know to not re-initialize this function, incrementCallback, every time it re-renders.

I did let it know to only re-initialize, when the counter state variable gets updated.

If I pass an empty array dependency, I can only use the function once.

If I don’t pass a second parameter, incrementCallback gets re-initialized every time the React component re-renders.

Conclusion

99% of the time you don’t need to use these optimization tools.

And everything comes at a cost. In this case, it comes with more complexity.

But that’s up to you to decide whether it’s worth it or not.

I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!