The useMemo hook in React Native memoizes the result of computations between component renders, preventing repeated execution of expensive operations. Unlike useCallback, which memoizes a function, useMemo preserves the returned value and recalculates it only when the specified dependencies change. According to React Docs, 2024, memoization is especially effective for computations with large arrays and complex data transformations. In React Native, every unnecessary re-render creates additional load on the bridge connection between JavaScript and native threads, so proper use of useMemo directly affects the smoothness of animations and interface response speed.
Key Takeaways
useMemo — is a hook from the standard React library, available in React Native without additional packages. It memoizes the value returned by the passed function and reuses this value on subsequent renders until the dependencies specified in the array change.
The hook's name comes from memoization — an optimization technique where the result of an expensive function is stored in a cache. On subsequent calls with the same arguments, the cached value is returned instead of recomputing.
In the context of React Native, memoization is especially important due to architectural features. Each component re-render sends data through the JavaScript — Native bridge, which takes time. If a component contains expensive computations (filtering a list, sorting, formatting), each re-render will repeat them, blocking the JS thread and causing frame drops.
According to React Native Performance Docs, 2024, the bottleneck is most often not the rendering of native components, but the execution of JavaScript logic between renders. useMemo solves precisely this problem.
useMemo takes a function and a dependency array, returning a memoized value. React stores the previous value and the dependency array. On each render, React compares the current dependencies with the previous ones using Object.is. If at least one dependency has changed, the function is executed again and the result is stored.
The useMemo signature is identical on the web and in React Native. The first argument is a parameterless function returning the memoized value. The second is a dependency array, upon whose changes the value will be recalculated.
import React, { useMemo } from 'react';
const sortedList = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
In this example, sortedList is recalculated only when the reference to the items array changes. If the array content changed but the reference remained the same (mutation), useMemo will not detect the changes — this is an important limitation.
React uses the Object.is algorithm to compare dependencies, which works similarly to strict equality === but handles NaN correctly (+0 and -0 are considered different). This means that for primitive types (strings, numbers, booleans), comparison works by value, while for objects and arrays — by reference.
// Object.is({'a': 1}, {'a': 1}) -> false (different refs)
// Object.is(42, 42) -> true (primitive by value)
// Object.is(NaN, NaN) -> true (correct handling of NaN)
Understanding this mechanism is critical: if you pass a new object to dependencies on every render, memoization will be useless because the dependencies will be considered changed each time.
useMemo is justified in three scenarios: expensive computations, passing stable props to child components, and preserving referential identity of objects. In React Native, all three scenarios occur regularly due to the architecture of mobile applications.
If a component performs processing of large data arrays (filtering, sorting, grouping) or resource-intensive mathematical operations, useMemo prevents repeating these computations on every re-render. In mobile applications, a typical example is formatting data from an API before displaying it in a list.
When a child component is wrapped in React.memo, it only re-renders when its props change. If a prop object is created inside the parent without useMemo, a new reference will be created on every parent render, and the child component will re-render unnecessarily, negating the benefit of React.memo.
In React Native, styles often depend on props — for example, element width is calculated based on screen size. useMemo allows computing such dynamic styles only when the input parameters change.
useMemo is not a universal optimization tool. In several scenarios, it provides no benefit and can even worsen performance due to the overhead of storing and comparing dependencies. In React Native, where every byte of memory matters, blindly applying useMemo without measuring its effect is an anti-pattern.
The hook brings no benefit in three main cases. First, if the computation is trivial (simple addition, string concatenation), the cost of useMemo exceeds the cost of the computation itself. Second, if dependencies change every render — the function will still execute, and memoization only adds extra work. Third, if the component renders infrequently, the cache storage overhead is not justified.
According to Kent C. Dodds, 2023, before adding useMemo, you should measure the problem using React DevTools Profiler or the built-in Performance Monitor in React Native. If a component re-render takes less than 1 ms, memoization is unnecessary.
useMemo and useCallback — two memoization hooks from React that are often confused. The difference lies in what they preserve: useMemo returns the result of executing a function (any value), while useCallback returns the function itself. Both take a dependency array, but the syntax differs.
| Characteristic | useMemo | useCallback |
|---|---|---|
| Returns | Result of function execution | Reference to the function |
| First argument | Function returning a value | Function to be memoized |
| Typical usage | Caching computations | Stable callbacks for child components |
| Equivalence | useMemo(() => fn, deps) | useCallback(fn, deps) === useMemo(() => fn, deps) |
In practice, useCallback is syntactic sugar over useMemo for cases when you need to memoize a function. In React Native, both hooks are used equally often: useMemo — for data (formatted text, computed styles), useCallback — for event handlers (onPress, onChangeText).
Let’s look at two real-world scenarios for using useMemo in React Native applications. The first is filtering a contact list by search query, the second is computing dynamic styles based on screen size.
In this example, useMemo prevents repeated filtering of a large contact list on every render if neither the search query nor the source data has changed.
const ContactList = ({ contacts, searchQuery }) => {
const filteredContacts = useMemo(() => {
if (!searchQuery.trim()) return contacts;
const query = searchQuery.toLowerCase();
return contacts.filter((c) =>
c.name.toLowerCase().includes(query) ||
c.phone.includes(query)
);
}, [contacts, searchQuery]);
return (
<FlatList
data={filteredContacts}
renderItem={renderContact}
keyExtractor={(item) => item.id}
/>
);
};
Without useMemo, filtering would execute on every render, including those triggered by animations or state changes in other parts of the component. With useMemo, filtering runs only when contacts or searchQuery changes.
In React Native, styles often depend on screen dimensions or component props. useMemo allows computing such a style object once and reusing it until the dependencies change.
const Card = ({ title, isSelected }) => {
const cardStyle = useMemo(() => ({
backgroundColor: isSelected ? '#e3f2fd' : '#ffffff',
borderWidth: isSelected ? 2 : 1,
padding: 16,
}), [isSelected]);
return (
<View style={cardStyle}>
<Text>{title}</Text>
</View>
);
};
This approach ensures that the cardStyle object remains stable (same reference) until isSelected changes. If Card is wrapped in React.memo, this pattern prevents unnecessary re-renders of child elements.
Frequently Asked Questions
useMemo returns a memoized value — the result of executing the function passed as the first argument. On subsequent renders, React returns the cached value if the dependencies have not changed.
useMemo returns the result of function execution (any value: number, object, JSX), while useCallback returns the function itself. Note that useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).
useMemo is useless for trivial computations (addition, concatenation), infrequent re-renders, dependencies that change on every render, and primitive types. Always measure performance before adding useMemo.
Yes, if used unnecessarily. React stores previous values in memory and compares dependencies on every render. For simple computations, the overhead of these operations exceeds the benefit of memoization.
Use React DevTools Profiler to measure component render times. In React Native, the Performance Monitor is also available through the developer menu. If a re-render takes less than 1 ms — useMemo is not needed.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also