In React, useMemo and usecallback are Hooks that help optimize the performance by memoizing values. They both accept a function as an argument and return a memoized version of the function.
useMemo
React useMemo
is a hook that lets you cache the result of a calculation between re-renders. It is useful when you want to avoid expensive calculations on every render, by caching the previous result.
To use useMemo
, you need to import it from React, and then call it with a function that returns the value you want to memoize, and an array of dependencies that determine when to re-run the function.
import { useState, useMemo } from "react";
const ExpensiveCalculation = ({ number }) => {
const calculateFactorial = (n) => {
if (n < 0) {
return -1;
}
if (n === 0 || n === 1) {
return 1;
}
return n * calculateFactorial(n - 1);
};
const factorial = useMemo(() => {
console.log("Calculating factorial");
return calculateFactorial(number);
}, [number]);
return (
<p>
{number}! = {factorial}
</p>
);
};
const App = () => {
const [number, setNumber] = useState(0);
const handleChange = (e) => {
setNumber(e.target.value);
};
return (
<div>
<h1>Expensive Calculation App</h1>
<input type="number" value={number} onChange={handleChange} />
<ExpensiveCalculation number={number} />
</div>
);
};
In this example, the App component has a number
state that controls the input value and the prop passed to the ExpensiveCalculation component. The ExpensiveCalculation component has a function that calculates the factorial of a given number, which is a potentially expensive operation.
useCallback
React useCallback
is a hook that lets you cache a function definition between re-renders. This can improve performance by preventing unnecessary re-rendering of components that depend on the function.
const cachedFn = useCallback(fn, dependencies)
To use useCallback
, you need to pass two parameters: the function you want to cache, and an array of dependencies that determine when the function should be updated.
import { useState, useEffect, useCallback } from "react";
const Timer = ({ start, stop }) => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
let interval = null;
if (start) {
interval = setInterval(() => {
setSeconds((s) => s + 1);
}, 1000);
} else if (!start && seconds !== 0) {
clearInterval(interval);
}
return () => clearInterval(interval);
}, [start, seconds]);
return (
<div>
<p>Seconds: {seconds}</p>
<button onClick={stop}>Stop</button>
</div>
);
};
const App = () => {
const [start, setStart] = useState(false);
const handleStart = useCallback(() => {
setStart(true);
}, []);
const handleStop = useCallback(() => {
setStart(false);
}, []);
return (
<div>
<h1>Timer App</h1>
<button onClick={handleStart}>Start</button>
<Timer start={start} stop={handleStop} />
</div>
);
};
In this example, Timer component uses useEffect
to set up and clear an interval that updates the seconds state every second. It also renders a button that calls the stop function prop to stop the timer. The App component has a start state that controls whether the Timer component should run or not.