Files
react.dev/src/content/reference/eslint-plugin-react-hooks/lints/component-hook-factories.md
Ricky c3d7560005 Blog post for React 19.2 (#8028)
* wip

* feedback and rm canary stuff

* tweak

* fix json

* more canary stuff

* fix link

* update dates

* update meta description

* Expand performance track section

* adjust linter note

* edit perf tracks down

* edit perf tracks down more

* tweak note

* tweak useEffectEvent

* formatting

* tweaks

* ppr

* rm canary stuff

* fix json

* fix json

* tweaks

* linter note

* nit

* nit

* link

* nit

* ppr

* missing await

* add lint v6

* fix link

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2025-10-01 17:42:52 -04:00

2.1 KiB

title
title
component-hook-factories

Validates against higher order functions defining nested components or hooks. Components and hooks should be defined at the module level.

This rule is available in eslint-plugin-react-hooks v6.

Rule Details {/rule-details/}

Defining components or hooks inside other functions creates new instances on every call. React treats each as a completely different component, destroying and recreating the entire component tree, losing all state, and causing performance problems.

Invalid {/invalid/}

Examples of incorrect code for this rule:

// ❌ Factory function creating components
function createComponent(defaultValue) {
  return function Component() {
    // ...
  };
}

// ❌ Component defined inside component
function Parent() {
  function Child() {
    // ...
  }

  return <Child />;
}

// ❌ Hook factory function
function createCustomHook(endpoint) {
  return function useData() {
    // ...
  };
}

Valid {/valid/}

Examples of correct code for this rule:

// ✅ Component defined at module level
function Component({ defaultValue }) {
  // ...
}

// ✅ Custom hook at module level
function useData(endpoint) {
  // ...
}

Troubleshooting {/troubleshooting/}

I need dynamic component behavior {/dynamic-behavior/}

You might think you need a factory to create customized components:

// ❌ Wrong: Factory pattern
function makeButton(color) {
  return function Button({children}) {
    return (
      <button style={{backgroundColor: color}}>
        {children}
      </button>
    );
  };
}

const RedButton = makeButton('red');
const BlueButton = makeButton('blue');

Pass JSX as children instead:

// ✅ Better: Pass JSX as children
function Button({color, children}) {
  return (
    <button style={{backgroundColor: color}}>
      {children}
    </button>
  );
}

function App() {
  return (
    <>
      <Button color="red">Red</Button>
      <Button color="blue">Blue</Button>
    </>
  );
}