Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use useCallback, useMemo and useEffect?

What is the main difference between useCallback, useMemo and useEffect?

Give examples of when to use each of them.

like image 600
Silicum Silium Avatar asked Jul 05 '19 23:07

Silicum Silium


People also ask

When should we use useCallback and useMemo?

useMemo is very similar to useCallback. It accepts a function and a list of dependencies, but the difference between useMemo and useCallback is that useMemo returns the memo-ized value returned by the passed function. It only recalculates the value when one of the dependencies changes.

In which situation would you use useMemo () in React?

React has a built-in hook called useMemo that allows you to memoize expensive functions so that you can avoid calling them on every render. You simple pass in a function and an array of inputs and useMemo will only recompute the memoized value when one of the inputs has changed.

Can I use useCallback in useEffect?

Hence, inside the List component, useEffect hook calls the setItems and prints “Fetching items” as its dependency has changed. The solution to the above problem: Here we can use the useCallback function to memoise the getItems() function depending upon the input number.

What is the difference between useEffect and useMemo?

The useMemo version immediately renders 1 . The useEffect version renders null , then after the component renders the effect runs, changes the state, and queues up a new render with 1 .


4 Answers

A short explanation.

useEffect

It's the alternative for the class component lifecycle methods componentDidMount, componentWillUnmount, componentDidUpdate, etc. You can also use it to create a side effect when dependencies change, i.e. "If some variable changes, do this".

useCallback

On every render, everything that's inside a functional component will run again. If a child component has a dependency on a function from the parent component, the child will re-render every time the parent re-renders even if that function "doesn't change" (the reference changes, but what the function does won't).
It's used for optimization by avoiding unnecessary renders from the child, making the function change the reference only when dependencies change. You should use it when a function is a dependency of a side effect e.g. useEffect.

useMemo

It will run on every render, but with cached values. It will only use new values when certain dependencies change. It's used for optimization when you have expensive computations. Here is also a good answer that explains it.

like image 169
Vencovsky Avatar answered Oct 16 '22 18:10

Vencovsky


useEffect() will let you create side effects on your components based on the dependencies you send to it.

function Example() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

ReactDOM.render(<Example />, document.getElementById('root'))
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="root"></div>

The example above is taken from the documentation of React. You can see that each time you click the button it will trigger an update on the count field (using setCount()) and then, the effect that depends on the count variable will trigger an update on the title of the page.


useCallback() will return a memoized callback. Normally, if you have a child component that receives a function prop, at each re-render of the parent component, this function will be re-executed; by using useCallback() you ensure that this function is only re-executed when any value on it's dependency array changes.

function ExampleChild({ callbackFunction }) {
  const [value, setValue] = React.useState(0);

  React.useEffect(() => {
    setValue(value + 1)
  }, [callbackFunction]);

  return (<p>Child: {value}</p>);
}

function ExampleParent() {
  const [count, setCount] = React.useState(0);
  const [another, setAnother] = React.useState(0);
  
  const countCallback = React.useCallback(() => {
    return count;
  }, [count]);
  
  return (
    <div>
      <ExampleChild callbackFunction={countCallback} />
      <button onClick={() => setCount(count + 1)}>
        Change callback
      </button>
      
      <button onClick={() => setAnother(another + 1)}>
        Do not change callback
      </button>
    </div>
  )
}

ReactDOM.render(<ExampleParent />, document.getElementById('root'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="root"></div>

useMemo() will return a memoized value that is the result of the passed parameter. It means that useMemo() will make the calculation for some parameter once and it will then return the same result for the same parameter from a cache.

This is very useful when you need to process a huge amount of data.

function ExampleChild({ value }) {
   const [childValue, setChildValue] = React.useState(0);

   React.useEffect(() => {
     setChildValue(childValue + 1);
   }, [value])

   return <p>Child value: {childValue}</p>;
}

function ExampleParent() {
  const [value, setValue] = React.useState(0);
  const heavyProcessing = () => {
    // Do some heavy processing with the parameter
    console.log(`Cached memo: ${value}`);
    return value;
  };

  const memoizedResult = React.useMemo(heavyProcessing, [value]);
  
  return (
    <div>
      <ExampleChild value={memoizedResult} />
      <button onClick={() => setValue(value + 1)}>
        Change memo
      </button>
    </div>
  )
}

ReactDOM.render(<ExampleParent />, document.getElementById('root'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="root"></div>
like image 34
d4vsanchez Avatar answered Oct 16 '22 20:10

d4vsanchez


Most minimal explanation:

useEffect:

Whenever you have some logic that is executed as reaction to a state change or before a change is about to happen.

useEffect(() => {
  // execute when state changed
  () => {
    // execute before state is changed
  }
}, [state]);

or in case of no dependency:

useEffect(() => {
  // execute when component has mounted
  () => {
    // execute when component will unmount
  }
}, []);

useCallback:

Whenever you have a function that is depending on certain states. This hook is for performance optimization and prevents a function inside your component to be reassigned unless the depending state is changed.

const myFunction = useCallback(() => {
  // execute your logic for myFunction
}, [state]);

Without useCallback, myFunction will be reassigned on every render. Therefore it uses more compute time as it would with useCallback.

useMemo

Whenever you have a value that is depending on certain state. Same as useCallback, useMemo is ment to reduce reassignments for performance optimization.

const myValue = useMemo(() => {
  // return calculated value
}, [state]); 

Same as useCallback, myValue is only assigned when state is changing and therefore will reduce compute time. Otherwise myValue will be reassigned on every render.

!Trick to mimick componentWillMount lifecycle

useMemo(() => {
  // execute componentWillMount logic
]}, []);

Since useEffect is called after the first render and then on every dependency change. It never runs before the first render. useMemo is executed inline with your JS therefore will be executed before it reaches your Components return statement.

!NOTE: functions with useCallback and values with useMemo can be used as dependency in useCallback, useMemo and useEffect. It is highly recommended to use these hooks in order to have a well structured and readable flow of state in your component. These hooks do not trigger a render. Only useState and useReducer do!

If you want to keep state that doesnt trigger a rerender or any of the above explained hooks you can use useRef. useRef will keep a value consistent over renders without triggering any state dependent value or effect.

like image 36
jpmarks Avatar answered Oct 16 '22 20:10

jpmarks


It's all well and good to know when to use the functions, but I wanted to know what the actual difference was between them! Here is what I found:

  • useMemo runs the code immediately, so the return value is available to code that comes after after it. This means it runs before the first render, so any useRef you are using to access HTML components won't be available on the initial run. (But you can add ref.current to the useMemo dependencies to have the useMemo code run again after the first render, when the useRef value has become available). Since the return value is available to code directly following it, this is why it is recommended for complex calculations that don't need to re-run on each render, as having the return value available immediately saves you from having to mess with the state to store the value now and access it later - just grab the return value of useMemo() and use it right away.
  • useEffect does not run immediately but runs after the first render. This means any useRef values referring to HTML elements will be valid on the first run. Since it runs after all the code in your function has finished and rendered, there is no point having a return value as there is no further code running that could use it. The only way useEffect code can do anything visible is by either changing the state to cause a re-render, or modifying the DOM directly.
  • useCallback is the same as useMemo except that it remembers the function itself rather than its return value. This means a useCallback function does not run immediately but can be run later (or not run at all), while useMemo runs its function immediately and just saves its return value for later use. Unlike useMemo this is not good for complex calculations as the code will run again every time it is used. If you ever pass a callback function as a prop to another component in your render function, make sure you're passing the return value of useCallback. If you make your callback function like const onClick = () => { ... } or in JSX as onClick={() => { ... }} then every render you will get a new instance of the function, so the child component will always re-render as it thinks you're changing the callback to a different function on every single render. But useCallback returns the same instance of the function each time, so the child function may skip the render completely if nothing else changed, making your app more responsive.

For example, if we pass the same function to both useMemo and useCallback:

let input = 123;
const output = useMemo(() => {
  return input + 1;
}, [
  input,
]);

// The above function has now run and its return value is available.

console.log( output ); // 124

input = 125; // no effect as the function has already run
console.log( output ); // 124
let input = 123;
const output = useCallback(() => {
  return input + 1;
}, [
  input,
]);

// The above function has not run yet but we can run it now.

console.log( output() ); // 124

input = 125; // changes the result as the function is running again
console.log( output() ); // 126

Here, useCallback has remembered the function and will keep returning the original function on future renders until the dependencies change, while useMemo actually runs the function immediately and just remembers its return value.

Both useCallback() and useMemo() provide return values that can be used immediately, while useEffect() does not because its code does not run until much later, after the render has completed.

like image 12
Malvineous Avatar answered Oct 16 '22 18:10

Malvineous