oxc-project/oxc · error

React Hook {hook_name:?} cannot be called inside a callback.

Error message

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.

What it means

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.

Source

Thrown at crates/oxc_linter/src/rules/react/rules_of_hooks.rs:157

            "Hooks in class components should have a containing class span"
        );

        let mut labels = vec![hook_span.primary_label("Hook is called here")];
        if let Some(class_component_span) = class_component_span {
            labels.push(class_component_span.label("Class component is defined here."));
        }

        OxcDiagnostic::warn(format!(
            "React Hook {hook_name:?} cannot be called in a class component. React Hooks \
            must be called in a React function component or a custom React \
            Hook function."
        ))
        .with_labels(labels)
        .with_error_code_scope(SCOPE)
    }

    pub(super) fn generic_error(span: Span, hook_name: &str) -> OxcDiagnostic {
        OxcDiagnostic::warn(format!(
            "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."
        ))
        .with_label(span.label("This Hook call is inside a nested callback."))
        .with_error_code_scope(SCOPE)
    }

    pub(super) fn use_effect_event_reference(
        span: Span,
        name: &str,
        called: bool,
    ) -> OxcDiagnostic {
        let mut message = format!(
            r#"`{name}` is a function created with React Hook "useEffectEvent", and can only be called from Effects and Effect Events in the same component."#
        );

        if !called {

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Hoist the Hook call to the top level of the component/custom Hook, then close over its result inside the callback.
  2. For effects that need async/timer logic, keep the hook outside and put only the side effect inside `useEffect(() => {...})`.
  3. Replace per-item hooks with a child component (`items.map(i => <Row id={i} />)` where Row calls the hook) or a batching hook.
  4. 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.

Example fix

// before
function List({ ids }) {
  return ids.map((id) => {
    const data = useQuery(id); // hook inside a callback
    return <Row data={data} />;
  });
}

// after
function List({ ids }) {
  return ids.map((id) => <Row key={id} id={id} />);
}
function Row({ id }) {
  const data = useQuery(id); // hook at top level of a component
  return <li>{data.name}</li>;
}
Defensive patterns

Strategy: validation

Validate before calling

oxlint --react-plugin src/ # rules-of-hooks
# or in CI: npx eslint . --rule '{"react-hooks/rules-of-hooks": "error"}'

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/83bf39e20e9f74ac. Report an issue: GitHub.