~3 min read • Updated Oct 22, 2025
Introduction
In React, using multiple useState hooks to manage related values like data, loading, and error can lead to impossible states. For example, the UI might show both a loading spinner and an error message at the same time. To avoid such inconsistencies, we can consolidate related states into a single useReducer hook.
Combining States with useReducer
Instead of managing each state separately, we define a unified reducer with a complex state object:
const [stories, dispatchStories] = React.useReducer(
storiesReducer,
{ data: [], isLoading: false, isError: false }
);Dispatching Actions for Transitions
We use dispatchStories to trigger state transitions during data fetching:
dispatchStories({ type: 'STORIES_FETCH_INIT' });
fetch(`${API_ENDPOINT}react`)
.then((response) => response.json())
.then((result) => {
dispatchStories({
type: 'STORIES_FETCH_SUCCESS',
payload: result.hits,
});
})
.catch(() =>
dispatchStories({ type: 'STORIES_FETCH_FAILURE' })
);Reducer Function with Complex State
The reducer handles all transitions and ensures consistency:
const storiesReducer = (state, action) => {
switch (action.type) {
case 'STORIES_FETCH_INIT':
return { ...state, isLoading: true, isError: false };
case 'STORIES_FETCH_SUCCESS':
return { ...state, isLoading: false, isError: false, data: action.payload };
case 'STORIES_FETCH_FAILURE':
return { ...state, isLoading: false, isError: true };
case 'REMOVE_STORY':
return {
...state,
data: state.data.filter(
(story) => action.payload.objectID !== story.objectID
),
};
default:
throw new Error();
}
};Rendering Based on Unified State
We now access loading, error, and data from a single state object:
{stories.isError && <p>Something went wrong ...</p>}
{stories.isLoading ? (
<p>Loading ...</p>
) : (
<List list={searchedStories} onRemoveItem={handleRemoveStory} />
)}Conclusion
By consolidating related states into a single useReducer hook, we avoid impossible states and gain more predictable, maintainable control over our UI. This approach is especially powerful for managing asynchronous data and complex state transitions in React applications.
Written & researched by Dr. Shahin Siami