React.memo
If your component renders the same result given the same props, you can wrap it in a call to React.memo
for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result.
React.memo
only checks for prop
changes. If your function component wrapped in React.memo
has a useState
, useReducer
or useContext
Hook in its implementation, it will still rerender when state or context change.
Counter.tsx
function Counter() {
const [counter, setCounter] = useState(0);
console.log("Counter : " + Date.now());
return (
<div className="mx-4 my-2">
<div>
Count : {counter}
</div>
<div>
<button type="button" className="btn"
onClick={event => setCounter(prevState => prevState + 1)}>Increase
</button>
<button type="button" className="btn"
onClick={event => setCounter(prevState => prevState - 1)}>Decrease
</button>
</div>
<Logger/>
</div>
);
}
export default Counter;
Logger.tsx ( Before using React.memo )
function Logger() {
return (
<div>
Logger Component
{console.log("Logger : " + Date.now())}
</div>
);
}
export default Logger;
Logger.tsx ( After using React.memo )
function Logger() {
return (
<div>
Logger Component
{console.log("Logger : " + Date.now())}
</div>
);
}
export default React.memo(Logger);
Custom Comparison Function
By default it will only shallowly compare complex objects in the props object. If you want control over the comparison, you can also provide a custom comparison function as the second argument.
function MyComponent(props) {
/* render using props */
}
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
export default React.memo(MyComponent, areEqual);
useMemo
Pass a “create” function and an array of dependencies. useMemo
will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render.
Remember that the function passed to useMemo
runs during rendering. Don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect
, not useMemo
.
If no array is provided, a new value will be computed on every render.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useCallback
Pass an inline callback and an array of dependencies. useCallback
will return a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate
).
useCallback(fn, deps)
is equivalent to useMemo(() => fn, deps)
.
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Should you use React.memo() or useMemo()?
Choosing between React.memo()
and useMemo()
should be straightforward. Now you have a good understanding of both of them.
- Use
React.memo
to memoize an entire component.
- Use
useMemo
to memoize a value within a functional component.
References
https://reactjs.org/docs/react-api.html#reactmemo
https://reactjs.org/docs/hooks-reference.html#usememo
https://reactjs.org/docs/hooks-reference.html#usecallback
https://blog.bitsrc.io/react-memo-vs-usememo-5730b90f0682