~2 min read • Updated Oct 22, 2025
Introduction
React’s useState hook is great for managing simple state. But when multiple state values are related or dependent, useReducer becomes a better choice. In this article, we migrate story-related state from useState to useReducer and explore how to manage multiple transitions declaratively.
Creating the Reducer Function
Start by defining a reducer outside the component. It receives state and action and returns a new state:
const storiesReducer = (state, action) => {
switch (action.type) {
case 'SET_STORIES':
return action.payload;
case 'REMOVE_STORY':
return state.filter(
(story) => action.payload.objectID !== story.objectID
);
default:
throw new Error();
}
};Using useReducer in the Component
Replace useState with useReducer in the App component:
const [stories, dispatchStories] = React.useReducer(
storiesReducer,
[]
);Now use dispatchStories to update state instead of setStories.
Dispatching Actions
When data is fetched asynchronously, dispatch an action to set the stories:
getAsyncStories()
.then((result) => {
dispatchStories({
type: 'SET_STORIES',
payload: result.data.stories,
});
});To remove a story, dispatch another action:
const handleRemoveStory = (item) => {
dispatchStories({
type: 'REMOVE_STORY',
payload: item,
});
};Why useReducer?
- Centralizes state logic in one place
- Improves readability and maintainability
- Supports multiple related state transitions
- Encourages declarative programming
Conclusion
Using useReducer in React allows for more structured and scalable state management. By handling multiple transitions like setting and removing stories, we move from imperative logic to declarative control. This approach is especially useful when managing complex or interdependent state in larger applications.
Written & researched by Dr. Shahin Siami