This error occurs when a useMemo callback function doesn't return a value, causing the memoized value to be undefined. The useMemo hook expects its callback to always return a value that will be cached and reused across renders.
The React useMemo hook is designed to memoize computed values to optimize performance by avoiding expensive recalculations on every render. When you call useMemo, you pass it a callback function that performs calculations and returns a value. This return value is what gets memoized (cached) and reused when the dependencies haven't changed. When the callback function doesn't have an explicit return statement, it implicitly returns undefined. This defeats the entire purpose of useMemo because you're just memoizing undefined instead of your intended computed value. The hook still works technically, but you won't get the value you need in your component. This is a common mistake because developers sometimes confuse useMemo (which returns a value) with useCallback (which returns a function) or useEffect (which doesn't return anything meaningful). Unlike useEffect, which is used for side effects, useMemo is specifically for computing and caching values.
The most common fix is to add a return statement. If you have a multi-line callback with curly braces, you must explicitly return the value:
// WRONG - no return
const value = useMemo(() => {
const result = expensiveCalculation(a, b);
}, [a, b]);
// CORRECT - explicit return
const value = useMemo(() => {
const result = expensiveCalculation(a, b);
return result;
}, [a, b]);The value you return can be of any type: primitives, objects, arrays, or even other functions.
For simple calculations, you can use the implicit return syntax by omitting curly braces:
// Implicit return - no curly braces needed
const doubled = useMemo(() => count * 2, [count]);
// Or for object returns, wrap in parentheses
const userInfo = useMemo(() => ({
name: firstName + ' ' + lastName,
age: calculateAge(birthDate)
}), [firstName, lastName, birthDate]);This is cleaner for simple one-line computations and eliminates the possibility of forgetting the return keyword.
If you're trying to memoize a function (not a value), you should use useCallback instead:
// WRONG - useMemo for a function
const handleClick = useMemo(() => {
console.log('Clicked!');
}, []);
// CORRECT - useCallback for functions
const handleClick = useCallback(() => {
console.log('Clicked!');
}, []);useMemo returns the result of calling the function, while useCallback returns the function itself.
If your useMemo callback has conditional logic, make sure all branches return something:
// WRONG - some paths don't return
const value = useMemo(() => {
if (condition) {
return computeA();
}
// Missing return for else case
}, [condition]);
// CORRECT - all paths return
const value = useMemo(() => {
if (condition) {
return computeA();
}
return computeB();
}, [condition]);Add a default return statement at the end to cover all cases.
After adding the return, check that you're returning the correct value type:
// If you expect an array
const filteredItems = useMemo(() => {
return items.filter(item => item.active);
}, [items]);
// If you expect an object
const config = useMemo(() => {
return {
theme: mode === 'dark' ? darkTheme : lightTheme,
fontSize: size
};
}, [mode, size]);Use TypeScript to enforce the return type if possible: useMemo<YourType>(() => ...)
Add the react-hooks ESLint plugin to catch this issue automatically:
npm install eslint-plugin-react-hooks --save-devThen in your ESLint config:
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}This will provide warnings when useMemo callbacks don't return values.
After fixing the return statement, verify the value is being properly memoized:
const MyComponent = ({ items }) => {
const sortedItems = useMemo(() => {
console.log('Computing sorted items');
return [...items].sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
console.log('Sorted items:', sortedItems); // Should show array, not undefined
return (
<ul>
{sortedItems.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
};The computation should only run when dependencies change, and the value should always be defined.
The useMemo hook is part of React's performance optimization toolkit, but it shouldn't be used everywhere. Only use useMemo for expensive calculations that you've profiled and confirmed are causing performance issues. Premature optimization with useMemo can actually make your code harder to read without meaningful performance gains.
When debugging useMemo issues, remember that React may choose to "forget" memoized values in some cases (like during development mode with Strict Mode) and recalculate them. This is intentional behavior to help catch bugs.
If you find yourself frequently forgetting to return values, consider whether your team should establish a convention of always using implicit returns for simple useMemo calls, or using explicit returns with early guards for complex logic. TypeScript can also help catch these issues at compile time by inferring the return type.
For complex objects or arrays, make sure you understand that useMemo compares dependencies using Object.is, which means object and array dependencies need to be stable references. If you pass a new object/array as a dependency on every render, useMemo will recalculate every time, defeating the purpose of memoization.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite