ref – https://www.geeksforgeeks.org/when-to-use-usecallback-usememo-and-useeffect/
useCallback
useCallBack demo
Let’s see this in the following code, doubleFactory creates and returns a function:
|
function doubleFactory(){ return (a) => 2*a; } const double1 = doubleFactory(); const double2 = doubleFactory(); double1(8); // gives 16 double2(8); // gives 16 double1 === double2; // false double1 === double1; // true |
doube1 and double2 doubles the value passed to them and are created by the same factory function. The two functions even when they share the same code, are not equal, here (double1 === double2) evaluates to false.
When to use useCallback: In React, a component usually has some callback function created within it.
|
function MyComponent(){ // HandleChange is created on every render const handleChange = () => {...}; return <> ... </>; } |
handleChange function objects are different on every rendering of MyComponent. And there are several cases when we may want the same function object between multiple renderings.
In our example, we have getItems which is executed whenever we enter some digits.
We pass this inside a child component List to be rendered.
So her’es how it works. Our input is being changed inside input element. Since the state changes, our variables (such as getItems) will also change and get re-calculated.
And since getItems is passed into List component, it will see that if getItems has changed, then it needs to re-render.
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
import React, { useState} from "react" import List from "./List" function App(){ const [input, setInput] = useState(1); const [light, setLight] = useState(true); const getItems = () => { return [input + 10, input + 100]; } {/* Style for changing the theme */} const theme = { backgroundColor: light ? "White": "grey", color: light ? "grey" : "white" } return <> <div style={theme}> <input type="number" value={input} onChange={event => setInput(parseInt(event.target.value))} /> <button onClick={() => setLight(prevLight => !prevLight)}> {light ? "dark mode":"light mode"} </button> <List getItems={getItems} /> </div> </>; } export default App; |
In our List, we look at getItems array. If it changes, we update and set our items to this new getItems.
List
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
import React, { useEffect, useState } from "react" function List({ getItems }){ /* Initial state of the items */ const [items, setItems] = useState([]); /* This hook sets the value of items if getItems object changes */ useEffect(() => { console.log("Fetching items"); setItems(getItems()); }, [getItems]); /* Maps the items to a list */ return <div> {items.map(item => <div key={item}>{item}</div>)} </div> } export default List; |
So
1) parent input state changes from Input Element
2) state change makes everything re-calculate, including getItems.
3) Since getItems is passed into child component, child sees getItems has changed, and thus, will re-render via useEffect.
The following will be the output when a user enters a number into the input field.

It can be seen from the console log that when the app is rendered for the first time, items are fetched, and “fetching items” are printed. Now if we input some different numbers, we see that items are fetched once again. This is the expected result.
Now the weird thing is,
when we press the button to change the theme,
we see that the getItems is still being called…even when the input field is not modified!

The reason behind this behavior is that when we press the button,
the app component is rerendered
and hence the function getItems() inside App is again created and we know that two objects are referentially different and thus re-rendered.
But why does the the button press trigger the component to re-reproduce getItem() again?
Because useState causes a re-render on the call to the setState method. It does not have any dependencies like useMemo or useEffect. This is why our component re-renders.
This is why getItem get called again even though the input field is not modified.
Thus, 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.
|
const getItems = useCallback(() => { return [input + 10, input + 100]; }, [input]); |
We don’t want to recreate the function unless the input changes, and hence, on pressing the button (changing the theme) items will not be fetched.
Now we use the useCallback hook to memoize the getitems function which takes the function and a dependency list. The dependency list in our case includes only the input.

useMemo
There are two cases where using useMemo can be helpful:
Case 1
When a component uses a value computed using a time-consuming function.
|
function MyComponent(){ const [data, setData] = useState(0); const number = verySlowFunction(data); return <div>{number}</div>; } function verySlowFunction(input){ ...heavy work done here return value; } |
Here the slow function is called every time MyComponent is rendered, maybe because some stateful variable is changed or some other component caused the rerendering.
Solution: By memoizing the returned value of the slow function using the useMemo hook we can save ourselves from the delay it may cause.
|
function MyComponent(){ const [data, setData] = useState(0); const number = useMemo(() => { return verySlowFunction(data)}, [data]); return <div>{number}</div>; } function verySlowFunction(input){ ...heavy work done here return value; } |
here we use the useMemo hook to cache the returned value and the dependency list contains the data stateful variable. Now every time the component is rendered, if the data variable is not altered, we get the memoized value without calling the CPU intensive function. Hence, it improves the performance.
Case 2
Now consider another scenario when we have a component that does something when some data changes, for example, a let’s take the hook useEffect which logs if some dependency changes.
|
function MyComponent() { const [number, setNumber] = useState(0); const data = { key: value }; useEffect(() => { console.log('Hello world'); }, [data]); } |
In the above code, every time the component is rendered, “Hello world” is printed on the console due to the fact that the data object that is stored in the previous render is referentially different in the next render and hence the useEffect hook runs the console.log function. In real-world useEffect can contain some functionality that we don’t want to be repeated if its dependencies do not change.
Solution: We can memoize the data object using the useMemo hook so that rendering of the component won’t create a new data object and hence useEffect will not call its body.
|
function MyComponent(){ const [number, setNumber] = useState(0); const data = useMemo( () => { return { key: value }}, number); useEffect(() => { console.log('Hello world'); }, [data]); } |
Now when the component renders for the second time and if the number stateful variable is not modified then console.log() is not executed.
useEffect
useEffect: In react, side effects of some state changes are not allowed in functional components. useEffect is always called after the render phase of the component. This is to avoid any side-effects from happening during the render commit phase (as it’d cause the component to become highly inconsistent and keep trying to render itself). This hook takes a function to be executed and a list of dependencies, changing which will cause the execution of the hook’s body.
To understand its proper use. let’s see a simple example:
Example: Consider a scenario where we have to fetch some data from some API once the components are mounted. In the example code, we simulate the server with our data object with values of different colours and fruits. We want to print the list of items depending on the button being pressed. Hence we have two state variables currentChoice and items which are modified by pressing the buttons. When a button is pressed it changes the currentChoice and the body of useEffect is called and current choice’s items are printed using a map. Now if we don’t use useEffect, every time a button is pressed data will be fetched from the server even if the choice does not change. In such a condition this hook helps us to not call the fetching logic unless our choice changes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
import React, { useEffect, useState} from "react" function App(){ /* Some data */ const data = { Colors: ["red", "green", "yellow"], Fruits: ["Apple", "mango", "Banana"] } /* Initial states */ const [currentChoice, setCurrentChoice] = useState("Colors"); const [items, setItems] = useState([]); /* Using useEffect to set the data of currentchoice to items and console log the fetching... */ useEffect(() => { setItems(data[currentChoice]); console.log("Data is fetched!"); }, [currentChoice]); return <> <button onClick={() => setCurrentChoice("Colors")}>Colors</button> <button onClick={() => setCurrentChoice("Fruits")}>Fruits</button> {items.map(item => {return <div key={item}>{item}</div>})} </>; } export default App; |
When the application loads for the first time, data is fetched from our fake server. This can be seen in the console in the image below. And when we press the Fruits button, appropriate data is again fetched from the server and we can see that “Data is fetched” is again printed in the console. But if we press the Fruits button again, we don’t have to get the data from the server again as our choice state does not change.
Hence, a useCallback hook should be used when we want to memoize a callback,
and to memoize the result of a function to avoid expensive computation we can use useMemo.
useEffect is used to produce side effects to some state changes.
usMemo vs useCallback
useMemo recalculates a value if the elements in its dependency array change (if there are no dependencies – i.e. the array is empty, it will recalculate only once). If the array is left out, it will recalculate on every render…just like useEffect. The difference herein lies in that it runs during the render of the component and not before.
useEffect is called after each render when a certain state has changed in the dependency array, or is left out altogether. If the array is empty, it will only be run once on the initial mount (and unmount if you return a cleanup function).