Difference between useEffect and useMemo - reactjs

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.

Related

Warning 'React hook useEffect has a missing dependency'

In a React app I get this warning on a few components in the useEffect function. I have seen other SO questions but still cant see a fix.
React Hook useEffect has a missing dependency: 'digiti' and 'time'. Either include it or remove the dependency array
const GenerateNumber = (props) => {
const [number, setNumber] = useState(0);
// add side effect to component
useEffect(() => {
const interval = setInterval(
() => setNumber(Math.floor(Math.random() * 9 + 1)),
50
);
setTimeout(() => { clearInterval(interval); setNumber(props.digiti); }, props.times * 100);
}, []);
return (
<span className='digit'>{number}</span>
);
}
This is something the react hooks exhaustive deps explain. In general, your dependency array should include all values used in the dependency array, however when you do this with something like setNumber, your useEffect hook will run infinitely as each change of setNumber triggers a new render (and each new render triggers setNumber, see the problem there?).
Your actual error, with the prop values of both digiti and times aim at you adding these two values to the dependency array, which would case the useEffect hook to run again every time these props change. It is up to you if this is intended behavior.
What is actually documented in the dependency array documentation is that it is intended behavior to leave the array empty to have the useEffect hook run exactly once.

useCallback vs useEffect in React

What's the different between useEffect when you pass it dependencies as the second parameter and useCallback?
Don't both essentially run the function/code passed as the first parameter whenever the dependencies passed as the second parameter change?
From what I've read the two hooks are intended to serve different purposes, but my question is whether they in actuality could be used interchangeably because they functionally do the same thing
They're too different.
useEffect will run the function inside when the dependency array changes.
useCallback will create a new function when the dependency array changes.
You can't switch useEffect with useCallback alone because you also need the logic to run the newly created function. (I suppose you could implement this if you used a ref as well, but that'd be quite strange.)
You can't switch useCallback with useEffect because you very often don't want to run the newly created function immediately - rather, you usually want to pass it as a prop to some other component.
useCallback primarily exists for optimization purposes, to reduce re-renders of a child component.
No, They are not same.
useEffect - is used to run side effects in the component when something changes. useEffect does
not return you anything. It just runs a piece of code in the component.
useCallback - Whereas useCallback returns a function, it does not execute the code actually. It is important to understand that
functions are objects in Javascript. If you don't use useCallback, the function you define inside the component is
re-created whenever the component rebuilds.
Example
Consider this example, this component will go in a infinite loop. Think Why?
const TestComponent = props => {
const testFunction = () => {
// does something.
};
useEffect(() => {
testFunction();
// The effect calls testFunction, hence it should declare it as a dependency
// Otherwise, if something about testFunction changes (e.g. the data it uses), the effect would run the outdated version of testFunction
}, [testFunction]);
};
Because on each render the testFunction
would be re-created and we already know that ueEffect will run the code when ever the testFunction changes. And since testFunction changes on each render, the useEffect will keep on running, and hence an infinite loop.
To fix this, we have to tell react, hey please don't re-create the testFunction on each render, create it only on first render (or when something changes on which it depends).
const TestComponent = props => {
const testFunction = useCallback(() => {
// does something.
}, []);
useEffect(() => {
testFunction();
// The effect calls testFunction, hence it should declare it as a dependency
// Otherwise, if something about testFunction changes (e.g. the data it uses), the effect would run the outdated version of testFunction
}, [testFunction]);
};
This won't be a infinite loop, since instance of testFunction will change only on first render and hence useEffect will run only once.
useEffect will run the function inside when the dependency array changes.
useCallback will create a new function when the dependency array changes.
Let's take an example, If I run the below code and click the first button it'll always rerender MemoComponent as well. Why because every time
we are passing new onClick function to this. To avoid re-rendering of MemoComponent what we can do is wrap onClick to useCallback. Whenever you want to create a new function pass state to the dependence array.
If you want to perform some action on state change you can write inside useEffect.
const Button = ({ onClick }) => {
console.log("Render");
return <button onClick={onClick}>Click</button>;
};
const MemoComponent = React.memo(Button);
export default function Home() {
const [state, setState] = useState(1);
useEffect(() => {
console.log(state); // this will execute when state changes
}, [state]);
const onClick = () => {};
// const onClick = useCallback(() => {},[])
return (
<main>
<button onClick={() => setState(1 + state)}>{state}</button>
<MemoComponent onClick={onClick} />
</main>
);
}
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".
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
useEffect(() => {
// execute when state changed
() => {
// execute before state is changed
}
}, []);
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.
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.

Why React expects me to add setters as useEffects dependencies

I am trying to use an async function inside a useEffect callback.
There is a behavior i don't understand (in my case related to the throttle function from lodash).
I don't get what is happing, and how to solve it, here is a sample of the code:
import throttle from 'lodash/throttle';
const myRequestWrapped = throttle(myRequest, 300);
const [name, setName] = useState('');
useEffect(() => {
myRequest(name) // No warning
myRequestWrapped(name); // React Hook useEffect has a missing dependency: 'myRequestWrapped'. Either include it or remove the dependency array
}, [ name ]);
If i add myRequestWrapped as a dependency, i have an infinite loop (the effect is triggered continuously).
I guess the throttle method works with a timer and it returns a different result at every run so i can understand why the infinite loop.
But i really don't understand why React wants it as a dependency (especially that it works without adding it !).
What is the logic?
Why myRequestWrapped and not myRequest?
Should i ignore the warning or do you know a clean way to solve that?
Thanks.
Its not React that wants you to add myRequestWrapped as a dependency but its eslint.
Also you must note that ESLint isn't aware of the programmers intention so it just warns the user if there is a scope of error being made.
Hooks heavily rely on closures and sometimes its difficult to figure out bugs related to closures and that is why eslint prompts if there is a case of a fucntion of variabled used within useEffect that might reflect the updated values.
Of course the check isn't perfect and you could carefully decide whether you need to add a dependency to useEffect or not.
If you see that what you wrote is perfectly correct. You can disable the warning
useEffect(() => {
myRequest(name);
myRequestWrapped(name);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ name ]);
Also you must not that throttle function cannot be used within render of functional componentDirectly as it won't be effective if it sets state as the reference of it will change
The solution here is to use useCallback hook. Post that even if you add myRequestWrapped as a dependency to useEffect you won't be seeing an infinite loop since the function will only be created once as useCallback will memoize and return the same reference of the function on each render.
But again you must be careful about adding dependency to useCallback
import throttle from 'lodash/throttle';
const Comp = () => {
const myRequestWrapped = useCallback(throttle(myRequest, 300), []);
const [name, setName] = useState('');
useEffect(() => {
myRequest(name);
myRequestWrapped(name);
}, [ name ]);
...
}
Shubham is right: it's not REACT, but ESLint instead (or TSLint, depending on the Linter you are using).
If I may add, the reason why the Linter suggest you to add myRequestWrapped is because of how the closures work in JavaScript.
To let you understand, take this easier example (and I need this because I would need to know what it's inside myRequestWrapped:
const MyComp = props => {
const [count, setCount] = React.useState(0);
const handleEvent = (e) => {
console.log(count);
}
React.useEffect(() => {
document.body.addEventListener('click', handleEvent);
return () => { document.body.removeEventListener('click', handleEvent); }
}, []);
return <button onClick={e => setCount(s => s +1)}>Click me</button>
}
So, right now, when MyComp is mounted, the event listener is added to the document.body, and anytime the click event is triggered, you call handleEvent, which will log count.
But, since the event listener is added when the component is mounted, the variable count inside handleEvent is, and always will be, equal to 0: that is because the instance of handleEvent created when you added the event listener is just one, the one that you associated with the event listener.
Instead, if you would write the useEffect like this:
React.useEffect(() => {
document.body.addEventListener('click', handleEvent);
return () => { document.body.removeEventListener('click', handleEvent); }
}, [handleEevent]);
Anytime the handleEvent method is updated, also your event listener is updated with the one handleEvent, thus when clicking on the document.body you will always log the latest count value.

What's the difference between useCallback and useMemo

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?

What's the difference between useCallback and useMemo in practice?

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

Resources