{"record":{"id":"83bf39e20e9f74ac","repo":"oxc-project/oxc","slug":"react-hook-hook-name-cannot-be-called-inside-a","errorCode":null,"errorMessage":"React Hook {hook_name:?} cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.","messagePattern":"React Hook (.+?) cannot be called inside a callback\\. React Hooks must be called in a React function component or a custom React Hook function\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/oxc_linter/src/rules/react/rules_of_hooks.rs","lineNumber":157,"sourceCode":"            \"Hooks in class components should have a containing class span\"\n        );\n\n        let mut labels = vec![hook_span.primary_label(\"Hook is called here\")];\n        if let Some(class_component_span) = class_component_span {\n            labels.push(class_component_span.label(\"Class component is defined here.\"));\n        }\n\n        OxcDiagnostic::warn(format!(\n            \"React Hook {hook_name:?} cannot be called in a class component. React Hooks \\\n            must be called in a React function component or a custom React \\\n            Hook function.\"\n        ))\n        .with_labels(labels)\n        .with_error_code_scope(SCOPE)\n    }\n\n    pub(super) fn generic_error(span: Span, hook_name: &str) -> OxcDiagnostic {\n        OxcDiagnostic::warn(format!(\n            \"React Hook {hook_name:?} cannot be called inside a callback. React Hooks \\\n            must be called in a React function component or a custom React \\\n            Hook function.\"\n        ))\n        .with_label(span.label(\"This Hook call is inside a nested callback.\"))\n        .with_error_code_scope(SCOPE)\n    }\n\n    pub(super) fn use_effect_event_reference(\n        span: Span,\n        name: &str,\n        called: bool,\n    ) -> OxcDiagnostic {\n        let mut message = format!(\n            r#\"`{name}` is a function created with React Hook \"useEffectEvent\", and can only be called from Effects and Effect Events in the same component.\"#\n        );\n\n        if !called {","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/react/rules_of_hooks.rs#L139-L175","documentation":"Diagnostic from oxlint's port of react-hooks/rules-of-hooks. This generic variant fires when a React Hook (any `use*` call other than the `use()` builtin) is called inside an anonymous function or arrow used as a function argument (a callback) that itself lives inside a component or custom Hook. Hooks rely on stable call order per render; a callback may run zero, multiple, or out-of-order times, which corrupts React's hook state bookkeeping.","triggerScenarios":"Per the rules_of_hooks run() logic: the Hook's parent function is a `Function { id: None }` or arrow that is a non-React function argument, and `is_somewhere_inside_component_or_hook` is true — e.g. `useEffect(() => { setTimeout(() => { setVisible(true) /* any useX here */ }, 100) })`, `items.map(id => useQuery(id))`, render-prop children ` <Foo>{() => useContext(X)}</Foo>` inside a component, event-handler props like `onClick={() => useToggle()}`. Named helper functions and class components produce sibling diagnostics (function_error / class_component), not this one.","commonSituations":"Data fetching inside `.map` callbacks (pre-react-query muscle memory); calling setState-ish hooks inside timers/listeners created in useEffect (the setter itself is fine — calling `useState` there is not); conditionally calling hooks behind early-return callbacks; render-props in design-system components.","solutions":["Hoist the Hook call to the top level of the component/custom Hook, then close over its result inside the callback.","For effects that need async/timer logic, keep the hook outside and put only the side effect inside `useEffect(() => {...})`.","Replace per-item hooks with a child component (`items.map(i => <Row id={i} />)` where Row calls the hook) or a batching hook.","Only call the same hooks in the same order every render — never behind conditions, loops, or callbacks; if you must gate, gate the callback, not the hook."],"exampleFix":"// before\nfunction List({ ids }) {\n  return ids.map((id) => {\n    const data = useQuery(id); // hook inside a callback\n    return <Row data={data} />;\n  });\n}\n\n// after\nfunction List({ ids }) {\n  return ids.map((id) => <Row key={id} id={id} />);\n}\nfunction Row({ id }) {\n  const data = useQuery(id); // hook at top level of a component\n  return <li>{data.name}</li>;\n}","handlingStrategy":"validation","validationCode":"oxlint --react-plugin src/ # rules-of-hooks\n# or in CI: npx eslint . --rule '{\"react-hooks/rules-of-hooks\": \"error\"}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only call hooks at the top level of components/custom hooks — never in callbacks, loops, or conditionals.","Hoist hooks out of .map/timers/handlers; put only side effects inside callbacks.","Enable react-hooks rules in the editor (fast feedback) and CI (enforcement).","Note the exception: the `use()` builtin is exempt; classic hooks are not."],"tags":["react","hooks","rules-of-hooks","oxlint","lint","correctness"],"backgroundTag":"react-invalid-hook-call","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}