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

  1. Incorrectly Passing a Component Instance Instead of a Component Definition:

    • Diagnosis: Look at where you’re using React.memo. If you see something like const MemoizedComponent = React.memo(MyComponent()); or React.memo(<MyComponent />), you’re passing the result of calling MyComponent (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.memo expects 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.
  2. Passing a Variable That Holds an Instance or undefined:

    • Diagnosis: Check if the variable you’re passing to React.memo might have been assigned an instance of your component or undefined due 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.memo needs the function reference to compare props and avoid re-rendering. If the variable is undefined or holds a React element, it fails.
  3. Using React.memo on 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.memo to 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.memo needs to wrap a functional or class component type, not a component instance created by calling the type.
  4. Typo in Component Name or Variable:

    • Diagnosis: A simple typo can lead to passing undefined or a wrong value to React.memo. For example, intending to memoize MyComponent but accidentally typing MyComponet (missing 'n').
    • Fix: Carefully review the component name you’re passing to React.memo and 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, which React.memo cannot process.
  5. Passing a Class Component Directly Without React.memo’s Wrapper:

    • Diagnosis: React.memo is 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), and MyClassComponent is indeed a class, the error might arise if the class itself isn’t structured as a valid React component type for memo to 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.memo acts 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, not React.memo.
    • Why it works: React.memo expects a component type. A class definition in JavaScript is a type (a constructor function), so passing MyClassComponent (the class itself) is correct. The error implies this wasn’t what was passed.
  6. 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 to React.memo the 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.memo to the actual component after it’s loaded. React.lazy handles the loading and rendering, and React.memo should wrap the component definition that React.lazy eventually uses, or you wrap the result of React.lazy if that result is a valid component type (which it is for React.lazy). The typical pattern is:
      const 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 }));
      
      The most common scenario for this error with React.lazy is trying to React.memo the result of the import() call before it’s resolved, or mistaking the import() function itself for the component.
    • Why it works: React.memo needs 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.

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.

Want structured learning?

Take the full React course →