The React.memo component is failing because it received a non-function value for its render function, meaning it doesn’t know how to render the component it’s supposed to be memoizing.
Common Causes and Fixes
-
Incorrectly Passing a Component Instance Instead of a Component Definition:
- Diagnosis: Look at where you’re using
React.memo. If you see something likeconst MemoizedComponent = React.memo(MyComponent());orReact.memo(<MyComponent />), you’re passing the result of callingMyComponent(an instance) instead of the component itself. - Fix: Remove the parentheses and any props if you’re trying to pass the component definition directly. It should be
const MemoizedComponent = React.memo(MyComponent);. - Why it works:
React.memoexpects a function (a component definition) as its first argument.MyComponent()or<MyComponent />executes that function and returns a React element, which is not a function.
- Diagnosis: Look at where you’re using
-
Passing a Variable That Holds an Instance or
undefined:- Diagnosis: Check if the variable you’re passing to
React.memomight have been assigned an instance of your component orundefineddue to conditional rendering or a typo. For example:let ComponentToMemoize = undefined; if (someCondition) { ComponentToMemoize = <MyActualComponent />; // Incorrectly assigns an instance } const Memoized = React.memo(ComponentToMemoize); - Fix: Ensure the variable holds the component definition. If it’s conditionally assigned, make sure the assignment is to the component function itself, not an invocation of it.
let ComponentToMemoize = MyActualComponent; // Correctly assigns the component definition if (someCondition) { // ... logic that doesn't reassign ComponentToMemoize to an instance } const Memoized = React.memo(ComponentToMemoize); - Why it works:
React.memoneeds the function reference to compare props and avoid re-rendering. If the variable isundefinedor holds a React element, it fails.
- Diagnosis: Check if the variable you’re passing to
-
Using
React.memoon a Component That Was Already Instantiated:- Diagnosis: This is common in higher-order components (HOCs) or when creating memoized components within loops or conditional blocks where the component is already being rendered or instantiated.
function withMemo(WrappedComponent) { return class extends React.Component { render() { return <WrappedComponent {...this.props} />; } }; } const MyComponent = () => <div>Hello</div>; const Wrapped = withMemo(MyComponent); const MemoizedWrapped = React.memo(Wrapped()); // Incorrect: calling Wrapped() - Fix: Apply
React.memoto the component definition before it’s instantiated or wrapped.function withMemo(WrappedComponent) { return class extends React.Component { render() { return <WrappedComponent {...this.props} />; } }; } const MyComponent = () => <div>Hello</div>; const MemoizedMyComponent = React.memo(MyComponent); // Memoize the base component const Wrapped = withMemo(MemoizedMyComponent); // Wrap the memoized component - Why it works:
React.memoneeds to wrap a functional or class component type, not a component instance created by calling the type.
- Diagnosis: This is common in higher-order components (HOCs) or when creating memoized components within loops or conditional blocks where the component is already being rendered or instantiated.
-
Typo in Component Name or Variable:
- Diagnosis: A simple typo can lead to passing
undefinedor a wrong value toReact.memo. For example, intending to memoizeMyComponentbut accidentally typingMyComponet(missing 'n'). - Fix: Carefully review the component name you’re passing to
React.memoand ensure it matches the actual component definition exactly. - Why it works: JavaScript is case-sensitive and requires exact names. If the name doesn’t exist, it resolves to
undefined, whichReact.memocannot process.
- Diagnosis: A simple typo can lead to passing
-
Passing a Class Component Directly Without
React.memo’s Wrapper:- Diagnosis:
React.memois primarily for functional components. While it can wrap class components, it often behaves unexpectedly or requires specific patterns. If you’re trying to memoize a class component like this:React.memo(MyClassComponent), andMyClassComponentis indeed a class, the error might arise if the class itself isn’t structured as a valid React component type formemoto process, or if it’s being passed incorrectly. However, the most direct cause of this specific error message is usually passing a non-function. If you are passing a class, the error might be a symptom of something else. The error "Requires a Function" strongly suggests you’re not passing a function at all. - Fix: For class components,
React.memoacts as a shallow comparison wrapper. The primary fix remains ensuring you pass the class definition itself, not an instance.const MemoizedClass = React.memo(MyClassComponent);. If you intended to memoize a class component’s render output, that’s a different optimization strategy, notReact.memo. - Why it works:
React.memoexpects a component type. A class definition in JavaScript is a type (a constructor function), so passingMyClassComponent(the class itself) is correct. The error implies this wasn’t what was passed.
- Diagnosis:
-
Dynamic Imports or Code Splitting Mismanagement:
- Diagnosis: When using dynamic
import()for code splitting, the imported module is often a Promise that resolves to an object containing the component. If you try toReact.memothe Promise itself or the resolved object before extracting the component, you’ll get this error.const LazyComponent = React.lazy(() => import('./MyComponent')); // Incorrect: // const MemoizedLazy = React.memo(LazyComponent); // LazyComponent is a function that returns a Promise // Or: // import('./MyComponent').then(module => { // React.memo(module.default); // This is correct if module.default is the component // }); - Fix: Ensure you’re applying
React.memoto the actual component after it’s loaded.React.lazyhandles the loading and rendering, andReact.memoshould wrap the component definition thatReact.lazyeventually uses, or you wrap the result ofReact.lazyif that result is a valid component type (which it is forReact.lazy). The typical pattern is:
The most common scenario for this error withconst LazyComponent = React.lazy(() => import('./MyComponent').then(module => ({ default: React.memo(module.default) })) ); // Or, if you want to memoize the component *before* it's lazy loaded: const MyComponent = () => <div>Hello</div>; const MemoizedMyComponent = React.memo(MyComponent); const LazyMemoizedComponent = React.lazy(() => Promise.resolve({ default: MemoizedMyComponent }));React.lazyis trying toReact.memothe result of theimport()call before it’s resolved, or mistaking theimport()function itself for the component. - Why it works:
React.memoneeds a stable reference to a component function. Dynamic imports introduce asynchronicity, and you must ensure the function reference is captured correctly after the module has loaded and the component is available.
- Diagnosis: When using dynamic
The next error you’ll likely encounter after fixing this is a prop type mismatch or a performance regression if the memoization wasn’t actually needed or correctly configured.