useMemo and useCallback
Also called Memoization hooks
- Part of
- React Native Glossary
- Mentioned in
- ESLintHooksMemoizationReact CompilerReact.memo
- Updated
What is useMemo and useCallback in React Native?
useMemo caches a computed value and useCallback caches a function between renders, so they keep the same identity until one of their dependencies changes.
useMemo and useCallback are React hooks that remember something between renders. useMemo(() => compute(a), [a]) returns the cached result until a changes; useCallback(fn, [a]) returns the same function object until a changes. useCallback(fn, deps) is simply useMemo(() => fn, deps).
They solve two different problems:
- Expensive work. Sorting or filtering a few thousand items on every keystroke can block the JavaScript thread.
useMemoskips the work when the inputs have not changed. - Referential stability. JavaScript compares objects and functions by identity, so an inline
() => {}is a brand new value each render. That breaks React.memo on children, re-runs effects that list it as a dependency, and makes FlatList treatrenderItemas changed.
const visible = useMemo(() => items.filter(matches(query)), [items, query]);
const renderItem = useCallback(({ item }) => <Row item={item} onPress={select} />, [select]);
The most common misconception is that wrapping everything makes an app faster. useCallback on a handler passed to a plain, non-memoised component achieves nothing, because the child re-renders anyway when its parent does. The hooks also cost a little: a dependency comparison and retained memory on every render. Use them where a profiler or a memoised consumer gives them something to do.
The second trap is a wrong dependency array. Omit a dependency and you read stale values, a bug that only shows up later; the react-hooks/exhaustive-deps lint rule catches it.
With the React Compiler enabled, most manual useMemo and useCallback calls become unnecessary, since the compiler inserts equivalent caching at build time. See useMemo.