Maybe I misunderstood something, but useCallback Hook runs everytime when re-render happens.
I passed inputs - as a second argument to useCallback - non-ever-changeable constants - but returned memoized callback still runs my expensive calculations at every render (I'm pretty sure - you can check by yourself in the snippet below).
I've changed useCallback to useMemo - and useMemo works as expected β runs when passed inputs changes. And really memoizes the expensive calculations.
Live example:
'use strict';
const { useState, useCallback, useMemo } = React;
const neverChange = 'I never change';
const oneSecond = 1000;
function App() {
const [second, setSecond] = useState(0);
// This π expensive function executes everytime when render happens:
const calcCallback = useCallback(() => expensiveCalc('useCallback'), [neverChange]);
const computedCallback = calcCallback();
// This π executes once
const computedMemo = useMemo(() => expensiveCalc('useMemo'), [neverChange]);
setTimeout(() => setSecond(second + 1), oneSecond);
return `
useCallback: ${computedCallback} times |
useMemo: ${computedMemo} |
App lifetime: ${second}sec.
`;
}
const tenThousand = 10 * 1000;
let expensiveCalcExecutedTimes = { 'useCallback': 0, 'useMemo': 0 };
function expensiveCalc(hook) {
let i = 0;
while (i < tenThousand) i++;
return ++expensiveCalcExecutedTimes[hook];
}
ReactDOM.render(
React.createElement(App),
document.querySelector('#app')
);
<h1>useCallback vs useMemo:</h1>
<div id="app">Loading...</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
useMemo is intended to run the function and return a value at when the component renders (assuming one of the dependancies has changed). useCallback is intended to return a (memoized) function at render time, but does not actually call the function yet; typically you just pass this function to an onClick parameter or something like that.
You can use them interchangeably if called correctly, for example having useMemo return a function is equivalent to useCallback, or using useCallback and then calling the returned function is similar to useMemo
useMemo() makes the function run only when inputs change. Else it returns the memoized(cached) result. It is only suggested to use useMemo() for functions involving complex calculations(more time complexity) as there is cost in running useMemo()
useCallback() prevents the new instance of the function(I mean function is redefined) being created on each rerender and thus prevents the rerendering of child components if we pass the function as props to them
Nowadays (25.05.2020), useCallback and useMemo can be used Interchangiably:
const fn = () => { function code }
const fn1 = React.useCallback(fn, deps)
const fn2 = React.useMemo(() => fn, deps)
In both cases, fn1 and fn2 is saved between different renders.
The difference is that useCallback might be a improved in the future where it always returns the same function and relays it to the last function that is passed to it.
I wrote about it here.
In your example, your function expensiveCalc in the useCallback will be run on every render because you are calling the memoized function directly below the useCallback on every render.
useCallback will memoize and return the actual function, so even though the function is memoized it will still be run whenever you call it.
In the example, this is essentially what is happening:
const calcCallback = () => expensiveCalc('useCallback');
const computedCallback = calcCallback();
In your case you should not use useCallback.
If possible move the expensive function outside of your react component and execute it outside as well.
e.g:
const calcResult = expensiveCalc('useCallback');
function App() {
If, for some reason, that is not possible this is where useMemo fits in.
useMemo will memoize the value that is returned from your function and will persist it between renders until your dependencies change.
This means if you do not want to run an expensive function on each render and only want the value, then either move it out of the scope of the react component or use useMemo.
For more details and info about the two hooks you can read more on this article: What is the difference between useMemo and useCallback?
Related
What is the main difference between useCallback, useMemo and useEffect?
Give examples of when to use each of them.
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.
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/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/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/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/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/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/umd/react-dom.development.js"></script>
<div id="root"></div>
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.
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.
useEffect
Gets called when the component mounts, unmounts and any of it's dependencies change.
Can be used to get data when component is mounted, subscribe and unsubscribe to event streams when component mounts and unmounts (think rxjs).
const [userId, updateUser] = useState(1);
useEffect(()=>{
//subscription
const sub = getUser(userId).subscribe(user => user);
// cleanup
return () => {
sub.unsubscribe();
}
},[userId]) // <-- Will get called again when userId changes
Can also be used for onetime method call which require no cleanup
useEffect(()=>{
oneTimeData();
},[]); // pass empty array to prevent being called multiple times
useCallback
Got functions that you don't want to be re-created on every component render?
Want a function that isn't called on component mount or unmount?
Use useCallback
const [val, updateValue] = useState(0);
const Compo = () => {
/* inc and dec will be re-created on every component render.
Not desirable a function does very intensive work.
*/
const inc = () => updateValue(x => x + 1);
const dec = () => updateValue(x => x - 1);
return render() {
<Comp1 onClick={inc} />
<Comp2 onClick={dec} />
}
}
useCallback to the rescue
const [val, updateValue] = useState(0);
const Compo = () => {
const callbackInc = useCallback(() => {
setCount(currentVal => currentVal + 1);
}, []);
const callbackDec = useCallback(() => {
setCount(currentVal => currentVal - 1);
}, []);
return render() {
<Comp1 onClick={callbackInc} />
<Comp2 onClick={callbackDec} />
}
}
If the argument passed to setCount isn't a function, then the variables you would want useCallback to 'watch' out for must be specified in the dependencies array less there will be no change effect.
const callbackInc = useCallback(() => {
setCount(val + 1); // val is an 'outside' variable therefore must be specified as a dependency
}, [val]);
useMemo
Doing heavy processing and want to memoize (cache) the results? Use useMemo
/*
heavyProcessFunc will only be called again when either val or val2 changes
*/
const result = useMemo(heavyProcessFunc(val, val2),[val,val2])
All of these hooks have the same goal: avoiding redundant component rebuilds (and re-execution of the stuff inside the hooks).
useEffect returns nothing (void) and thus is suitable for such cases.
useCallback returns a function which will be used later in the component. Unlike normal function declaration, it will not trigger component rebuild unless its dependencies change.
useMemo is just another flavour of useCallback.
Here is the best explanation I've seen so far.
I'm trying to wrap my head around what exactly the useMemo() React hook is.
Suppose I have this useMemo:
const Foo = () => {
const message = useMemo(() => {
return readMessageFromDisk()
}, [])
return <p>{message}</p>
}
Isn't that exactly the same as using a useState() and useEffect() hook?
const MyComponent = () => {
const [message, setMessage] = useState('')
useEffect(() => {
setMessage(readMessageFromDisk())
}, [])
return <p>{message}</p>
}
In both cases the useMemo and useEffect will only call if a dependency changes.
And if both snippes are the same: what is the benefit of useMemo?
Is it purely a shorthand notation for the above useEffect snippet. Or is there some other benefit of using useMemo?
useEffect is used to run the block of code if the dependencies change. In general you will use this to run specific code on the component mounting and/or every time you're monitoring a specific prop or state change.
useMemo is used to calculate and return a value if the dependencies change. You will want to use this to memoize a complex calculation, e.g. filtering an array. This way you can choose to only calculate the filtered array every time the array changes (by putting it in the dependency array) instead of every render.
useMemo does the same thing as your useEffect example above except it has some additional performance benefits in the way it runs under the hood.
In react, we can memoize a function using useCallback so the function doesn't change every rerender
const fn = useCallback(someOtherFn, []);
Instead, can we define someOtherFn outside the component, and if it uses setState, we give that to it as an argument?
Something like
function someOtherFn(setState) {
setState("ok")
}
function myComponenet(){
......
}
Sorry in advance if this is a stupid question.
You can do that, but it might probably defeat the purpose, since you'd have to write another function that calls it, and that other function would be created every render. For example, perhaps you're thinking of:
function someOtherFn(setState) {
setState("ok")
}
const MyComponent = () => {
const [state, setState] = useState();
return <button onClick={() => someOtherFn(setState)}>click</button>;
};
Although someOtherFn indeed wouldn't need to be created every time - it'd only need to be created once - the handler function, the
() => someOtherFn(setState)
would be created every time the component renders, which could be a problem in certain uncommon (IMO) situations.
To avoid this issue, you would have to bind the setState argument to the function persistently somehow - which would be most easily accomplished through the use useCallback.
What is the main difference between useCallback, useMemo and useEffect?
Give examples of when to use each of them.
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.
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/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/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/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/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/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/umd/react-dom.development.js"></script>
<div id="root"></div>
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.
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.
useEffect
Gets called when the component mounts, unmounts and any of it's dependencies change.
Can be used to get data when component is mounted, subscribe and unsubscribe to event streams when component mounts and unmounts (think rxjs).
const [userId, updateUser] = useState(1);
useEffect(()=>{
//subscription
const sub = getUser(userId).subscribe(user => user);
// cleanup
return () => {
sub.unsubscribe();
}
},[userId]) // <-- Will get called again when userId changes
Can also be used for onetime method call which require no cleanup
useEffect(()=>{
oneTimeData();
},[]); // pass empty array to prevent being called multiple times
useCallback
Got functions that you don't want to be re-created on every component render?
Want a function that isn't called on component mount or unmount?
Use useCallback
const [val, updateValue] = useState(0);
const Compo = () => {
/* inc and dec will be re-created on every component render.
Not desirable a function does very intensive work.
*/
const inc = () => updateValue(x => x + 1);
const dec = () => updateValue(x => x - 1);
return render() {
<Comp1 onClick={inc} />
<Comp2 onClick={dec} />
}
}
useCallback to the rescue
const [val, updateValue] = useState(0);
const Compo = () => {
const callbackInc = useCallback(() => {
setCount(currentVal => currentVal + 1);
}, []);
const callbackDec = useCallback(() => {
setCount(currentVal => currentVal - 1);
}, []);
return render() {
<Comp1 onClick={callbackInc} />
<Comp2 onClick={callbackDec} />
}
}
If the argument passed to setCount isn't a function, then the variables you would want useCallback to 'watch' out for must be specified in the dependencies array less there will be no change effect.
const callbackInc = useCallback(() => {
setCount(val + 1); // val is an 'outside' variable therefore must be specified as a dependency
}, [val]);
useMemo
Doing heavy processing and want to memoize (cache) the results? Use useMemo
/*
heavyProcessFunc will only be called again when either val or val2 changes
*/
const result = useMemo(heavyProcessFunc(val, val2),[val,val2])
All of these hooks have the same goal: avoiding redundant component rebuilds (and re-execution of the stuff inside the hooks).
useEffect returns nothing (void) and thus is suitable for such cases.
useCallback returns a function which will be used later in the component. Unlike normal function declaration, it will not trigger component rebuild unless its dependencies change.
useMemo is just another flavour of useCallback.
Here is the best explanation I've seen so far.
Maybe I misunderstood something, but useCallback Hook runs everytime when re-render happens.
I passed inputs - as a second argument to useCallback - non-ever-changeable constants - but returned memoized callback still runs my expensive calculations at every render (I'm pretty sure - you can check by yourself in the snippet below).
I've changed useCallback to useMemo - and useMemo works as expected β runs when passed inputs changes. And really memoizes the expensive calculations.
Live example:
'use strict';
const { useState, useCallback, useMemo } = React;
const neverChange = 'I never change';
const oneSecond = 1000;
function App() {
const [second, setSecond] = useState(0);
// This π expensive function executes everytime when render happens:
const calcCallback = useCallback(() => expensiveCalc('useCallback'), [neverChange]);
const computedCallback = calcCallback();
// This π executes once
const computedMemo = useMemo(() => expensiveCalc('useMemo'), [neverChange]);
setTimeout(() => setSecond(second + 1), oneSecond);
return `
useCallback: ${computedCallback} times |
useMemo: ${computedMemo} |
App lifetime: ${second}sec.
`;
}
const tenThousand = 10 * 1000;
let expensiveCalcExecutedTimes = { 'useCallback': 0, 'useMemo': 0 };
function expensiveCalc(hook) {
let i = 0;
while (i < tenThousand) i++;
return ++expensiveCalcExecutedTimes[hook];
}
ReactDOM.render(
React.createElement(App),
document.querySelector('#app')
);
<h1>useCallback vs useMemo:</h1>
<div id="app">Loading...</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
TL;DR;
useMemo is to memoize a calculation result between a function's calls and between renders
useCallback is to memoize a callback itself (referential equality) between renders
useRef is to keep data between renders (updating does not fire re-rendering)
useState is to keep data between renders (updating will fire re-rendering)
Long version:
useMemo focuses on avoiding heavy calculation.
useCallback focuses on a different thing: it fixes performance issues when inline event handlers like onClick={() => { doSomething(...); } cause PureComponent child re-rendering (because function expressions there are referentially different each time)
This said, useCallback is closer to useRef, rather than a way to memoize a calculation result.
Looking into the docs I do agree it looks confusing there.
useCallback will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).
Example
Suppose we have a PureComponent-based child <Pure /> that would re-render only once its props are changed.
This code re-renders the child each time the parent is re-rendered β because the inline function is referentially different each time:
function Parent({ ... }) {
const [a, setA] = useState(0);
...
return (
...
<Pure onChange={() => { doSomething(a); }} />
);
}
We can handle that with the help of useCallback:
function Parent({ ... }) {
const [a, setA] = useState(0);
const onPureChange = useCallback(() => {doSomething(a);}, []);
...
return (
...
<Pure onChange={onPureChange} />
);
}
But once a is changed we find that the onPureChange handler function we created β and React remembered for us β still points to the old a value! We've got a bug instead of a performance issue! This is because onPureChange uses a closure to access the a variable, which was captured when onPureChange was declared. To fix this we need to let React know where to drop onPureChange and re-create/remember (memoize) a new version that points to the correct data. We do so by adding a as a dependency in the second argument to `useCallback :
const [a, setA] = useState(0);
const onPureChange = useCallback(() => {doSomething(a);}, [a]);
Now, if a is changed, React re-renders the <Parent>. And during re-render, it sees that the dependency for onPureChange is different, and there is a need to re-create/memoize a new version of the callback. This is passed to <Pure> and since it's referentially different, <Pure> is re-rendered too. Finally everything works!
NB not just for PureComponent/React.memo, referential equality may be critical when use something as a dependency in useEffect.
useMemo and useCallback use memoization.
I like to think of memoization as remembering something.
While both useMemo and useCallback remember something between renders until the dependancies change, the difference is just what they remember.
useMemo will remember the returned value from your function.
useCallback will remember your actual function.
Source: What is the difference between useMemo and useCallback?
One-liner for useCallback vs useMemo:
useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).
With useCallback you memoize functions, useMemo memoizes any computed value:
const fn = () => 42 // assuming expensive calculation here
const memoFn = useCallback(fn, [dep]) // (1)
const memoFnReturn = useMemo(fn, [dep]) // (2)
(1) will return a memoized version of fn - same reference across multiple renders, as long as dep is the same. But every time you invoke memoFn, that complex computation starts again.
(2) will invoke fn every time dep changes and remember its returned value (42 here), which is then stored in memoFnReturn.
const App = () => {
const [dep, setDep] = useState(0);
const fn = () => 42 + dep; // assuming expensive calculation here
const memoFn = useCallback(fn, [dep]); // (1)
const memoFnReturn = useMemo(fn, [dep]); // (2)
return (
<div>
<p> memoFn is {typeof memoFn} </p>
<p>
Every call starts new calculation, e.g. {memoFn()} {memoFn()}
</p>
<p>memoFnReturn is {memoFnReturn}</p>
<p>
Only one calculation for same dep, e.g. {memoFnReturn} {memoFnReturn}
</p>
<button onClick={() => setDep((p) => p + 1)}>Change dep</button>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<div id="root"></div>
<script>var { useReducer, useEffect, useState, useRef, useCallback, useMemo } = React</script>
You are calling the memoized callback every time, when you do:
const calcCallback = useCallback(() => expensiveCalc('useCallback'), [neverChange]);
const computedCallback = calcCallback();
This is why the count of useCallback is going up. However the function never changes, it never *****creates**** a new callback, its always the same. Meaning useCallback is correctly doing it's job.
Let's making some changes in your code to see this is true. Let's create a global variable, lastComputedCallback, that will keep track of if a new (different) function is returned. If a new function is returned, that means useCallback just "executed again". So when it executes again we will call expensiveCalc('useCallback'), as this is how you are counting if useCallback did work. I do this in the code below, and it is now clear that useCallback is memoizing as expected.
If you want to see useCallback re-create the function everytime, then uncomment the line in the array that passes second. You will see it re-create the function.
'use strict';
const { useState, useCallback, useMemo } = React;
const neverChange = 'I never change';
const oneSecond = 1000;
let lastComputedCallback;
function App() {
const [second, setSecond] = useState(0);
// This π is not expensive, and it will execute every render, this is fine, creating a function every render is about as cheap as setting a variable to true every render.
const computedCallback = useCallback(() => expensiveCalc('useCallback'), [
neverChange,
// second // uncomment this to make it return a new callback every second
]);
if (computedCallback !== lastComputedCallback) {
lastComputedCallback = computedCallback
// This π executes everytime computedCallback is changed. Running this callback is expensive, that is true.
computedCallback();
}
// This π executes once
const computedMemo = useMemo(() => expensiveCalc('useMemo'), [neverChange]);
setTimeout(() => setSecond(second + 1), oneSecond);
return `
useCallback: ${expensiveCalcExecutedTimes.useCallback} times |
useMemo: ${computedMemo} |
App lifetime: ${second}sec.
`;
}
const tenThousand = 10 * 1000;
let expensiveCalcExecutedTimes = { 'useCallback': 0, 'useMemo': 0 };
function expensiveCalc(hook) {
let i = 0;
while (i < 10000) i++;
return ++expensiveCalcExecutedTimes[hook];
}
ReactDOM.render(
React.createElement(App),
document.querySelector('#app')
);
<h1>useCallback vs useMemo:</h1>
<div id="app">Loading...</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
Benefit of useCallback is that the function returned is the same, so react is not removeEventListener'ing and addEventListenering on the element everytime, UNLESS the computedCallback changes. And the computedCallback only changes when the variables change. Thus react will only addEventListener once.
Great question, I learned a lot by answering it.
useCallback() and useMemo() are pretty much same but useCallback saves the function reference in the memory and checks on the second render whether it's same or not if it is same then it returns last saved function without recreating it and if it is changed then it returns a new function and replaces it with older function in memory for future rendering.
useMemo works in same manner but it can't save your function but the computed or returned value. On every render useMemo checks the value if the returned value of your function is the same on second render then it will return same value without recalculating the function value and if the value is not same on second render then it will call the function and return new value and store it for future render.
NOTE: You have to be careful when you have need to use these hooks. Unnecessary use of these hooks can make your app performance worse because they use memory. Be sure if your component re-renders many times with heavy calculations then it is good to use these hooks.
Before knowing in detail about useCallback and useMemo hooks, letβs understand how the React compares the values added in dependency array of useEffect.
React compares these values by using Object.is() i.e., by referential equality. In general, for primitive data types the values are compared based on its value if they are equal then it is considered as similar otherwise they are treated as different and for non primitive data types (objects, arrays or functions) the values are compared based on the memory location reference, if the values shares the same memory location then they are known to be similar otherwise treated as different (Even though the two objects has same properties if the memory location reference is different then they are considered as not same).
Now, if the dependency of the useEffect is dependent on primitive data type values then there is no issue as we have already seen how the React would compare them. The problem is with non primitive data type values as we have already got to know that for the same two objects the memory location reference to be same in order for them to be considered as similar.
Now the question arises, how can we make the two same non primitive data values to be considered as similar. Yes, the only possible answer is to make them share the same memory location reference, now how do we actually do this?? Here comes useCallback and useMemo hooks which helps in storing the non primitive data type values under the same memory reference if there is no change in the values between the rendering.
Now, the useEffect can compare its non primitive dependencies and be made to run only if there is actual change in the dependencies.
If the function is used as dependency in the useEffect then, that function can be wrapped in the useCallback which returns memoized function i.e., returns same function definition stored under the same memory reference unless function dependency is not changed.
const memoizedFunc = useCallback(function useEffectDependentFunction(){
return someValue;
}, [useEffectDependentFunction_dependency])
// useEffectDependentFunction will be stored in the same memory location under the name memoizedFunc untill useEffectDependentFunction_dependency is not changed.
useEffect(()=>{
//do something
}, [memoizedFunc]}
If some array or object or value obtained after some calculation from a function is to be used as dependency in the useEffect then, that function which involves the calculation can be wrapped in useMemo which returns memoized array or object or value depending on what the use case is, unlike useCallback it wont return the function itself instead it returns the calculated value from the function.
const memoizedValue = useMemo(()=>function useEffectDependentValueYieldingFunction(){
//some calculation
return someValue;
}, [useEffectDependentValueYieldingFunction_dependency])
// the value returned from the useEffectDependentValueYieldingFunction will be stored in the same memory location under the name memoizedValue untill useEffectDependentValueYieldingFunction_dependency is not changed.
useEffect(()=>{
//do something
}, [memoizedValue]}
Thatβs it.
The above explained scenario is one of the use cases where useCallback and useMemo are used efficiently.
In both useMemo and useCallback, the hook accepts a function and an array of dependencies. The key different is:
useMemo will memory the returned value, it caches a value type.
Usecase: Using it for caching calculation value heavily.
useCallback will memory the function, it caches a function.
Usecase: Using it for caching API calling method which is only call by
action of user.
Cheer!
I think its also worth noting that there may be some other optimisations going on - for example useMemo might be storing the call history of every function execution in memory whereas useCallback probably would not have any need to do that.
The reason I say that is because there would be no purpose to storing a history of callbacks in memory as the callback will execute regardless but also because the purpose is to keep referential equality to prevent re-renders of children that use the function as props, so if the referenced changed (even to a previous reference) the function would re-render anyway