component-hook-factories
Disallows higher order functions that define components or hooks inside them.
This rule is currently in rc and only available in v3.0.0 rc releases.
Full Name in eslint-plugin-react-x@rc
react-x/component-hook-factoriesFull Name in @eslint-react/eslint-plugin@rc
@eslint-react/component-hook-factoriesPresets
x
recommended
recommended-typescript
recommended-type-checked
strict
strict-typescript
strict-type-checked
Rule Details
Defining components or hooks inside other functions (factory pattern) 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.
When a component or hook is defined inside another function:
- A new function identity is created on every call
- React cannot reconcile previous and next renders, so it unmounts and remounts
- All internal state is lost on every parent re-render
- It defeats memoization and optimization techniques
- Custom hooks created inside factories capture stale closures
Instead, define every component and hook at the top (module) level.
Common Violations
Invalid
// ❌ 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() {
// ...
};
}
// ❌ Hook defined inside a component
function MyComponent() {
function useLocalState() {
return useState(0);
}
// ...
}Valid
// ✅ Component defined at module level
function Component({ defaultValue }) {
// ...
}
// ✅ Custom hook at module level
function useData(endpoint) {
// ...
}
// ✅ Pass props instead of using a factory
function Button({ color, children }) {
return (
<button style={{ backgroundColor: color }}>
{children}
</button>
);
}
function App() {
return (
<>
<Button color="red">Red</Button>
<Button color="blue">Blue</Button>
</>
);
}Troubleshooting
I need dynamic component 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 values as props instead:
// ✅ Better: Pass values as props
function Button({ color, children }) {
return (
<button style={{ backgroundColor: color }}>
{children}
</button>
);
}
function App() {
return (
<>
<Button color="red">Red</Button>
<Button color="blue">Blue</Button>
</>
);
}I need a hook factory for configuration
Instead of a factory that creates hooks:
// ❌ Wrong: Hook factory
function createUseData(endpoint) {
return function useData() {
const [data, setData] = useState(null);
useEffect(() => {
fetch(endpoint).then((r) => r.json()).then(setData);
}, []);
return data;
};
}Accept configuration as hook parameters:
// ✅ Better: Pass configuration as parameters
function useData(endpoint) {
const [data, setData] = useState(null);
useEffect(() => {
fetch(endpoint).then((r) => r.json()).then(setData);
}, [endpoint]);
return data;
}Resources
Further Reading
- React Docs: Nesting and organizing components
- React Docs: Passing props to a component
- React Docs:
no-component-hook-factoriesLint Rule
See Also
react-x/no-nested-component-definitions
Disallows nesting component definitions inside other components.react-x/no-nested-lazy-component-declarations
Disallows nesting lazy component declarations inside other components.