How to use useCallback and useMemo
1)What is useMemo why do wee need it?
For this article, I assume that you’ve already read my post about React.memo, or at least have some knowledge of it.
Regarding the following code:
1import { memo, useMemo, useState } from 'react';
2
3const ChildComponent = memo( ({ studentInfo }: { studentInfo: { name: string ,age: number}}) =>{
4
5 useEffect(()=>{
6 console.log('child rerender')
7 })
8
9 return <>{studentInfo.name}, age {studentInfo.age}</>
10})
11
12const ParentComponent = () =>{
13
14 const [age,setAge] = useState(12)
15 const [counter,setCount] = useState(0)
16
17 const studentInfo = {
18 name: 'John',
19 age
20 }
21
22 return <>
23 <button onClick={()=>{ setAge(prev => prev += 1) }}>increase age</button>
24 <button onClick={()=>{ setAge(prev => prev -= 1) }}>descease age</button>
25 <button onClick={()=>{ setCount(prev => prev += 1) }}>change counter</button>
26
27 <br/>
28 <ChildComponent studentInfo={studentInfo}/>
29 <br/>
30 counter: {counter}
31 </>
32}
33We have a ChildComponent that’s wrapped with memo, meaning it will re-render only when the props passed to it change. Of course, when you increase or decrease the age in studentInfo, line 6 will log.
So what happens when we change the counter? You can clearly see that studentInfo doesn’t depend on it.

The Child component still re-renders, and line 6 logs — but why??
Every time the parent component re-renders (in this case, when the counter changes), a new studentInfo object is created. React uses shallow comparison to check whether the props have changed. A shallow comparison only checks the top level of objects or arrays — not their nested structures. Therefore, even though the content of studentInfo hasn’t changed, its object reference has, causing the component to re-render.
useMemo is a React Hook that memoizes (caches) the result of a computation between renders — so React only recomputes it when its dependencies change.
Now, let’s use useMemo for our example.
1const studentInfo = useMemo(()=>{
2 return {
3 name: 'John',
4 age
5 }
6 },[age])
7After we change the counter, no re-render happens for ChildComponent.

2) useCallback
useCallback is siminlar to useMemo, but is used for functions
Consider this code:
1
2import { memo, useEffect, useState } from 'react';
3
4const ChildComponent = memo( ({ caculateSalary }: { caculateSalary: any}) =>{
5
6 useEffect(()=>{
7 console.log('child rerender')
8 })
9
10 return <button onClick={()=> console.log(caculateSalary())}>show salary</button>
11})
12
13const ParentComponent = () =>{
14
15 const [salary,setSalary] = useState(1200)
16 const [counter,setCount] = useState(0)
17
18 const caculateSalary = ()=>{
19 return salary + 100// bonus
20 }
21
22 return <>
23 <button onClick={()=>{ setSalary(prev => prev += 1) }}>increase salary</button>
24 <button onClick={()=>{ setSalary(prev => prev -= 1) }}>descease salary</button>
25 <button onClick={()=>{ setCount(prev => prev += 1) }}>change counter</button>
26
27 <br/>
28 <ChildComponent caculateSalary={caculateSalary}/>
29 <br/>
30 counter: {counter}
31 </>
32}
33
34export { ParentComponent }
35
36Of course, when we change the counter, a new calculateSalary object will be created. React counts it as a props change, and the Child component re-renders.
We can simply prevent it by using useCallback
1
2 const caculateSalary = useCallback(()=>{
3 return salary + 100// bonus
4 },[salary])
5
6Now, calculateSalary is memoized and will only be recreated when its dependency (salary) changes.