React useMemo Hook
useMemo returns a memoized value.
What is memoization? You might ask, well it's prevents the reconstruction of objects during DOM re-renders. Almost like caching a value so that during DOM re-renders, it can serve the cached value.
Often useMemo is used to keep expensive and resource intensive functions from running during DOM re-renders.
let's take an example:
const heavyfunction = (number) => {
for(let i=0; i<20000; i++){
number += 1;
}
return number;
}
function Example() {
const [count, setCount] = useState(0);
const heavyValue = heavyfunction(0)
return (<div>
<button onClick={()=>setCount(c=>c-1)}>-</button>
<h3>Count: {count}</h3>
<button onClick={()=>setCount(c=>c+1)}>+</button>
</div>)
}
In this example heavyfunction
will run every time there is a count
state change and subsequent DOM re-render. That's unnecessary if you want heavyfuntion
to run during first DOM render. Well, we can use useMemo to memoize the heavyValue
. Here's how:
const heavyfunction = (number) => {
for(let i=0; i<20000; i++){
number += 1;
}
return number;
}
function Example() {
const [count, setCount] = useState(0);
const heavyValue = useMemo(()=>heavyfunction(0), [])
return (<div>
<button onClick={()=>setCount(c=>c-1)}>-</button>
<h3>Count: {count}</h3>
<button onClick={()=>setCount(c=>c+1)}>+</button>
</div>)
}
As you can see that useMemo can accept a dependency array just like useEffect and will run only if the values in array change. If the dependency array is empty, it will only run once on first DOM render.
React useCallback Hook
useCallback hook returns a memoized function.
Example:
function Example() {
const [count, setCount] = useState(0);
const [tasks, setTasks] = useState([])
const addTask = () => {
setTasks(ts => [...ts, "Task"])
}
return (<div>
<Tasks setTask={addTask} tasks={tasks}>
<button onClick={()=>setCount(c=>c-1)}>-</button>
<h3>Count: {count}</h3>
<button onClick={()=>setCount(c=>c+1)}>+</button>
</div>)
}
function Tasks ({addTask, tasks}) {
console.log('Tasks component rendered...')
return (
<>
<h3>All the tasks:</h3>
{tasks.map((task, index) => {
<span key={index}>{task}</span>
})}
<button onClick={addTask}>Add Task</button>
</>
)}
Here you can see, every time we press increment or decrement, the Tasks
component re-renders which is unnecessary. This is due to recreation of addTask
function and that leads to re-render of Tasks
component, how do we prevent this behavior? Well, enter useCallback
Hook and it takes a dependency array just like useMemo
:
function Example() {
const [count, setCount] = useState(0);
const [tasks, setTasks] = useState([])
const addTask = useCallback(() => setTasks(ts => [...ts, "Task"]), [tasks])
return (<div>
<Tasks setTask={addTask} tasks={tasks}>
<button onClick={()=>setCount(c=>c-1)}>-</button>
<h3>Count: {count}</h3>
<button onClick={()=>setCount(c=>c+1)}>+</button>
</div>)
}
function Tasks ({addTask, tasks}) {
console.log('Tasks component rendered...')
return (
<>
<h3>All the tasks:</h3>
{tasks.map((task, index) => {
<span key={index}>{task}</span>
})}
<button onClick={addTask}>Add Task</button>
</>
)}
Boom, now Tasks
component will only re-render when tasks
change and that is what we want. This hook is very useful in a dashboard design.
About BoomLabs:
BoomLabs is an agency providing new age web solutions. Our services include:
- Web Design and Development
- SEO (For SaaS and E-commerce businesses)
- Content writing using AI.