This error occurs when passing an invalid third argument to useReducer. The initializer must be a function reference that returns initial state, not the result of calling a function or an incorrect type.
The "useReducer invalid initializer" error indicates that the optional third argument passed to React's useReducer hook is not a valid initializer function. The useReducer hook accepts three arguments: the reducer function, the initial state (or initial argument), and an optional initializer function for lazy initialization. When you provide a third argument, React expects it to be a pure function that takes the second argument (initialArg) as input and returns the initial state. This initializer function runs only once during the first render, allowing you to defer expensive computations or perform conditional initialization logic. The error occurs when you pass something other than a function reference as the third argument, or when you accidentally pass the result of calling a function instead of the function itself. This is a runtime error that prevents the component from mounting correctly.
The most common mistake is calling the initializer function instead of passing the function itself. Check your useReducer call:
Incorrect:
// Don't call the function with ()
const [state, dispatch] = useReducer(reducer, initialArg, initFunction());Correct:
// Pass the function reference without calling it
const [state, dispatch] = useReducer(reducer, initialArg, initFunction);The initializer should be a function reference that React will call internally with the initialArg parameter.
Your initializer function must return a value that will be used as the initial state. Verify your function has a return statement:
// Correct initializer function
function init(initialArg) {
return {
count: initialArg,
timestamp: Date.now()
};
}
const [state, dispatch] = useReducer(reducer, 0, init);The function receives the second argument (initialArg) as its parameter and must return the complete initial state object.
If you're conditionally using an initializer, make sure you're not passing undefined or other non-function values:
Incorrect:
const initializer = someCondition ? initFunction : undefined;
const [state, dispatch] = useReducer(reducer, initialArg, initializer);Correct - omit third argument entirely if not needed:
const [state, dispatch] = someCondition
? useReducer(reducer, initialArg, initFunction)
: useReducer(reducer, initialArg);Only pass the third argument when you have a valid function to provide.
The initializer function must be synchronous and cannot be an async function. React calls this function during render and expects an immediate return value:
Incorrect:
// Async functions are not valid initializers
async function initAsync(initialArg) {
const data = await fetchData();
return { data };
}
const [state, dispatch] = useReducer(reducer, null, initAsync);Correct:
// Use synchronous initialization, handle async operations in useEffect
function init(initialArg) {
return { data: null, loading: true };
}
const [state, dispatch] = useReducer(reducer, null, init);
useEffect(() => {
fetchData().then(data => dispatch({ type: 'SET_DATA', payload: data }));
}, []);When using TypeScript, ensure your initializer function has the correct type signature:
type State = { count: number };
type Action = { type: 'increment' } | { type: 'decrement' };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
// Properly typed initializer function
function init(initialCount: number): State {
return { count: initialCount };
}
const [state, dispatch] = useReducer(reducer, 0, init);The initializer should accept the same type as your initialArg and return the state type.
If you don't need lazy initialization, you can simplify by using only two arguments:
Simple initialization (no third argument):
const initialState = { count: 0, timestamp: Date.now() };
const [state, dispatch] = useReducer(reducer, initialState);Lazy initialization (with third argument):
function init(initialCount) {
return { count: initialCount, timestamp: Date.now() };
}
const [state, dispatch] = useReducer(reducer, 0, init);Lazy initialization is beneficial when the initial state calculation is expensive or when you need to derive initial state from props. Otherwise, direct initialization is simpler and less error-prone.
When to use lazy initialization: Lazy initialization with the third argument is most useful when creating the initial state requires expensive computations (like parsing large JSON, complex calculations, or reading from localStorage), when you want to avoid recreating the initial state object on every render during development with Strict Mode, or when you need to compute initial state based on props or arguments.
Pure function requirement: The initializer function must be a pure function - it should always return the same result given the same input, have no side effects, and not rely on external state. React may call this function multiple times in development mode to help detect impurities.
TypeScript edge case: There's a known TypeScript type inference issue (GitHub issue #27052) where TypeScript may incorrectly require the third argument even when it's optional. If you encounter this, you can explicitly type your useReducer call or update your TypeScript and React type definitions to the latest versions.
Comparison with useState: While useState also supports lazy initialization with a function argument, useReducer's lazy initialization pattern is different - useState takes the function as the first argument, while useReducer takes it as the third argument with the initial value as the second argument passed to that function.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite