What is the useReducer Hook?
If you are a React developer, and haven’t learned about React hooks yet, it is the perfect time to start learning now. In this post, we are specifically going to learn about the useReducer Hook. In the previous post we have covered the useState hook. Make sure to read it before you get started with this post.
Note: If you are new to React, I would recommend learning Hooks first, and then learn older way of doing things if necessary.
‘Hooks are functions that let you “hook into” React state and lifecycle features from function component. They do not work within a class. They let you use React without a class.’ — React Official Blog post.
Alright! Let’s jump into useReducer Hook.
What is a Reducer?
Before, we learn this hook, there is also one more piece that we need to have an understanding on. What is a Reducer ? And how do I write a reducer without messing up?
I like to think of a Reducer in Redux as a “Coffee Maker”. It takes in an old state and action and brews a new state (Fresh coffee).
I like to think of a reducer like a “coffee maker”. The coffee maker takes in coffee powder and water. It then returns a freshly brewed cup of coffee that we can enjoy. Based on this analogy reducers are functions that take in the current state (coffee powder) and actions (water) and brew a new state (fresh coffee).
Reducers are pure functions that take in a state and action and return a new state.
A reducer should always follow the following rules:
Given a set of inputs, it should always return the same output. No surprises, side effects, API calls, mutations.
If you are new to the concept of reducers, I would suggest you read an article I wrote about it, before we proceed to learning the hook:
What is the useReducer Hook?
The useReducer is a hook I use sometimes to manage the state of the application. It is very similar to the useState hook, just more complex. It acts as an alternate hook to the useState hook to manage complex state in your application.
The useReducer hook uses the same concept as the reducers in Redux. It is basically a pure function, with no side-effects.
A function is considered pure, if it adheres to the following rules:
- The function always returns the same output if the same arguments are passed in.
- The function does not produce any side-effects.
With this, it makes reducers easier to test and write.
The syntax for the useReducer hook is as follows:
const [state, dispatch] = useReducer(reducer, initialArg, init);
The useReducer will basically allow React functional components to access the reducer functions from your application’s state management.
How to use the useReducer Hook?
We have already learned from the previous post, how to use the useState hook, to use state within a functional React component.
Now, let’s extend the same concept to use state within a functional React component, but this time with the useReducer hook.
First step is to import the useReducer hook.
import React, { useReducer } from "react";
Now we are going to setup an initial state, just like we do while using external libraries like Redux.
const initialState = { react: false, graphQL: false, angular: false };
Our example is going to be a simple component with three buttons, representing courses on different topics as shown below:
If the user clicks on any of the buttons, we are going to update the state and mark the course as completed.
The component is as shown as below:
const Courses = () => {
const [state, dispatch] = useReducer(counterReducer, initialState); const handleReactPress = () => {
dispatch({ type: "REACT" });
}; const handleGraphQLPress = () => {
dispatch({ type: "GRAPHQL" });
}; const handleAngularPress = () => {
dispatch({ type: "ANGULAR" });
}; return (
<div className="box">
<h2>Use Reducer Example Component</h2>
<p>
Learning{" "}
{state.react
? "React"
: state.graphQL
? "GraphQL"
: state.angular
? "Angular"
: "Not Started"}
</p>
<div>
<button
type="button"
onClick={handleReactPress}
className="button is-grey"
>
React
</button>
<button
type="button"
onClick={handleGraphQLPress}
className="button is-dark"
>
GraphQL
</button>
<button
type="button"
onClick={handleAngularPress}
className="button is-grey"
>
Angular
</button>
</div>
</div>
);
};
Now our component is ready, and it is time to define the reducer.
const coursesReducer = (state, action) => {
switch (action.type) {
case "REACT":
return { react: true };
case "GRAPHQL":
return { graphQL: true };
case "ANGULAR":
return { angular: true }; default:
throw new Error();
}
};
If you are already familiar with Redux, the reducer code here may look very familiar. The reducer takes in the state and action as parameters, and updates the state of the application, based on the action that was dispatched by the component.
Complete Example on Code Sandbox:
Do we not need Redux anymore?
Now this brings us to the million dollar question, do we need Redux anymore?
Well, the answer is not straightforward. With the introduction of the useReducer hook, we have the ability to manage a fair amount of complex state without the need for bringing in external libraries like Redux. But that doesn’t mean we may never need Redux anymore. This hook does not replace Redux or MobX.
This post by Eric Elliot is a good read on this topic: Do React Hooks Replace Redux?
Conclusion
This was post was originally published in https://programmingwithmosh.com/
Hooks is a fairly newer concept in React, and the official React documentation does not recommend that you rewrite all your components using Hooks. Instead, you can start writing your newer components using Hooks.
If you want to play with the code samples I used in this blog post, they are available on my GitHub Repo below:
Resources:
There are other hooks in addition to the useReducer hook, that we will cover in another blog post. I hope you enjoyed this post. Please share it and you can follow me on twitter at @AdhithiRavi