streamich/react-use · error · Error
useReducerContext must be used inside a ReducerProvider.
Error message
useReducerContext must be used inside a ReducerProvider.
What it means
Thrown by the hook returned from createReducerContext when it is called outside a matching <ReducerProvider>. The factory creates a React context defaulting to undefined; useReducerContext reads it via useContext and, when the value is null or undefined (== null), concludes no provider is supplying the [state, dispatch] tuple and throws. This is a structural wiring error, not a data error — the hook simply has no reducer state to read.
Source
Thrown at src/factory/createReducerContext.ts:30
const ReducerProvider = ({
children,
initialState,
}: {
children?: React.ReactNode;
initialState?: React.ReducerState<R>;
}) => {
const state = useReducer<R>(
reducer,
initialState !== undefined ? initialState : defaultInitialState
);
return providerFactory({ value: state }, children);
};
const useReducerContext = () => {
const state = useContext(context);
if (state == null) {
throw new Error(`useReducerContext must be used inside a ReducerProvider.`);
}
return state;
};
return [useReducerContext, ReducerProvider, context] as const;
};
export default createReducerContext;
View on GitHub (pinned to fbe99c6327)
Solutions
- Wrap the component subtree that calls useReducerContext in the <ReducerProvider> returned from the same createReducerContext call: <ReducerProvider><MyComponent/></ReducerProvider>.
- Verify you are using the hook and Provider from the SAME factory invocation — call createReducerContext once, export both members, and import both together; do not call the factory twice and mix the pairs.
- In tests/SSR, mount the consumer inside the provider (e.g. render(<ReducerProvider><Comp/></ReducerProvider>) in @testing-library) instead of rendering <Comp/> bare.
- If a portal or lazy boundary is involved, ensure the provider sits above the point where the portal/lazy tree resolves, or lift the provider to the root.
Example fix
// before
const [useReducerContext, ReducerProvider] = createReducerContext(reducer, init);
function Child() {
const [state, dispatch] = useReducerContext(); // throws: no provider above
return <p>{state}</p>;
}
export default function App() {
return <Child/>;
}
// after
export default function App() {
return (
<ReducerProvider>
<Child/>
</ReducerProvider>
);
} Defensive patterns
Strategy: validation
Validate before calling
// Structural: there is no pre-call probe for a context hook, so the // 'validation' is to render consumers only inside their provider. // Co-locate creation + provider + hook, and assert the tree shape: // // factory.ts export const [useReducerContext, ReducerProvider] = createReducerContext(reducer, init); // App.tsx — provider MUST wrap every consumer <ReducerProvider> <ConsumesReducer/> </ReducerProvider>
Type guard
// A context-consumer type guard: narrow a value to the [state, dispatch] tuple // before reading it, so you never call the hook on an unmounted/unprovided tree. const isReducerTuple = <S, A>( v: unknown ): v is [S, React.Dispatch<A>] => Array.isArray(v) && v.length === 2 && typeof v[1] === 'function'; // Note: the hook itself throws before you can apply this; the real guard is the // provider in the tree (see validationCode).
Try / catch
// Wrap the consumer subtree in an error boundary so a missing-provider throw
// surfaces a clear fallback instead of blanking the screen.
class ProviderBoundary extends React.Component<
{ children: React.ReactNode; fallback: React.ReactNode },
{ hasError: boolean }
> {
state = { hasError: false };
static getDerivedStateFromError() { return { hasError: true }; }
render() {
return this.state.hasError ? this.props.fallback : this.props.children;
}
}
// usage: <ProviderBoundary fallback={<p>ReducerProvider missing</p>}><Consumes/></ProviderBoundary> Prevention
- Call createReducerContext once at module scope and export the hook and Provider together so they can never diverge.
- Keep a single root provider high in the tree (above any lazy/portal boundaries) that contains all consumers.
- Add an ESLint rule or code review check that any file importing useReducerContext also renders within ReducerProvider.
- In tests, always mount consumers inside the provider via a shared test util.
When it happens
Trigger: Calling the useReducerContext hook (first element of the tuple returned by createReducerContext(reducer, defaultInitialState)) in a component that is not a descendant of the corresponding <ReducerProvider>. Also triggered if the wrong provider instance is used (e.g. calling createReducerContext twice and using hook A inside provider B, since each call makes a distinct context), or when a provider is conditionally rendered such that the consumer mounts outside it.
Common situations: Forgetting to wrap the app/subtree in <ReducerProvider>; creating the context at module scope but rendering the consumer in a sibling/portal that escapes the provider; copy-pasting the hook into a component defined in another file that was never wrapped; SSR/test renders that mount the consumer in isolation without the provider.
Related errors
- useStateContext must be used inside a StateProvider.
- useLocalStorage key may not be falsy
- states expected to be an object or array, got ${typeof state
- State '${state}' is not a valid state (does not exist in sta
- Capacity has to be greater than 1, got '${capacity}'
AI-assisted analysis of streamich/react-use@fbe99c6327 (2026-08-12).
Data as JSON: /api/errors/b1e8880d74af8831.
Report an issue: GitHub.