Introduction
In the
previous article, we have learned about the useContext() hook and how it is used in React. Now in this article, we will understand another hook named useReducer() hook, how it is used, and the purpose of using it.
What is Reducer?
Before starting about useReducer() hook, we first should know about Reduce in JavaScript.
The reduce() method in JavaScript executes a reducer function on each element of the array and provides a single value as output.
- Syntax- Array.reduce(<reducer func>,[initialValue])
This function takes 2 parameters - first is reducer function which itself takes 2 arguments.
So, let’s check an example.
- const array1 = [1, 2, 3, 4,5];
-
- const reducer = (accumulator, currentValue) => accumulator + currentValue;
-
-
-
- console.log(array1.reduce(reducer));
-
-
-
-
-
- console.log(array1.reduce(reducer, 6));
-
-
As per the example, the reducer function first takes an accumulative value and current value and passes these to array.reduce() method as an argument.
Now, we understand reducer and reduce function so let us move ahead for the useReducer() hook.
useReducer() hook
This hook is used for state management. This stands as an alternative for useState() hook. This is a hook that includes in React 16.7.0. It accepts a reducer function along with initial application state and returns the current application state.
Syntax
- useReducer(reducer,initialState)
reducer – here reducer is a callback function.
initialState – It is the initial value.
So, for better understanding of useReducer() hook, let’s see an example. Here, we will be creating a MathComponent.js that will include arithmetic operators to perform an operation.
- import React, { useReducer } from 'react'
-
- const initialState = 0
-
- const reducer = (state, action) => {
- switch (action) {
- case 'addition':
- return state + 1
- case 'subtraction':
- return state - 1
- case 'multiply':
- return state * 2
- case 'divide':
- return state / 2
- case 'reset':
- return initialState
- default:
- return state
- }
- }
-
- function MathComponent() {
-
- const[count,dispatch] = useReducer(reducer, initialState)
-
- return (
- <div>
- <div> Output is - {count}</div>
- <button onClick={() => dispatch('addition')}>Addition</button>
- <button onClick={() => dispatch('subtraction')}>Subtraction</button>
- <button onClick={() => dispatch('multiply')}>Multiplication</button>
- <button onClick={() => dispatch('divide')}>Division</button>
- <button onClick={() => dispatch('reset')}>Reset</button>
- </div>
- )
- }
-
- export default MathComponent
Now, we will be importing MathComponent.js in App.js.
- import React from 'react';
- import './App.css';
- import MathComponent from './components/MathComponent';
-
- function App() {
- return (
- <div className="App">
- <MathComponent/>
- </div>
- );
- }
-
- export default App;
The output will be as below.
Initially, it will display the initial value as 0.
Now, clicking on the Addition button will add value by 1 as many times as clicked.
Clicking on Subtract will reduce value by 1.
On clicking of multiplication, the current state value will be multiplied by 2.
Now, on clicking Division, it will divide the value by two.
When we click Reset, it will set to 0 again.
Let’s see the process.
First, the useReducer() method accepts reducer and initialState as a parameter.
As in the above image, the reducer method will take the current state and action that are needed to be performed in that method.
After calling useReducer, it will return the current state and dispatch method which act as a parameter as shown in the example.
Now, let’s move one step ahead.
Create another component named MathComplex.js and in place of a single variable in reduce method, we will be passing an object for both, state and action.
- import React, { useReducer } from 'react'
-
- const initialState = {
- value: 0
- }
-
- const reducer = (state, action) => {
- switch (action.type) {
- case 'addition':
- return { value: state.value + 1}
- case 'subtraction':
- return { value: state.value - 1}
- case 'multiply':
- return { value: state.value * 2}
- case 'divide':
- return {value: state.value / 2}
- case 'reset':
- return initialState
- default:
- return state
- }
- }
-
- function MathComplex() {
- const [count, dispatch] = useReducer(reducer, initialState)
-
- return (
- <div>
- <div> Output is - {count.value}</div>
- <button onClick={() => dispatch({ type: 'addition' })}>Addition</button>
- <button onClick={() => dispatch({ type: 'subtraction' })}>Subtraction</button>
- <button onClick={() => dispatch({ type: 'multiply' })}>Multiplication</button>
- <button onClick={() => dispatch({ type: 'divide' })}>Division</button>
- <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
- </div>
- )
- }
-
- export default MathComplex
The above example has an object for action which includes the type that will be rendered by the reduce method.
The output will be displayed the same as above.
Now, add 1 more counter variable and 2 other buttons that will perform the operations based on values passed from dispatch function.
- import React, { useReducer } from 'react'
-
- const initialState = {
- counter1: 0,
- counter2:0
- }
-
- const reducer = (state, action) => {
- switch (action.type) {
- case 'addition':
- return {...state, counter1: state.counter1 + action.value }
- case 'subtraction':
- return {...state, counter1: state.counter1 - action.value }
- case 'additionByVal':
- return {...state, counter2: state.counter2 + action.value }
- case 'subtractionByVal':
- return {...state, counter2: state.counter2 - action.value }
- case 'multiply':
- return {...state, counter1: state.counter1 * action.value }
- case 'divide':
- return {...state, counter1: state.counter1 / action.value }
- case 'reset':
- return initialState
- default:
- return state
- }
- }
-
- function MathComplex() {
- const [count, dispatch] = useReducer(reducer, initialState)
-
- return (
- <div>
- <div> Output is Counter 1 - {count.counter1}</div>
- <div> Output is Counter 2 - {count.counter2}</div>
- <button onClick={() => dispatch({ type: 'addition', value: 1 })}>Addition</button>
- <button onClick={() => dispatch({ type: 'subtraction', value: 1 })}>Subtraction</button>
- <button onClick={() => dispatch({ type: 'additionByVal', value: 5 })}>Addition By 5</button>
- <button onClick={() => dispatch({ type: 'subtractionByVal', value: 5 })}>Subtraction By 5</button>
- <button onClick={() => dispatch({ type: 'multiply', value: 2 })}>Multiplication</button>
- <button onClick={() => dispatch({ type: 'divide', value: 2 })}>Division</button>
-
- <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
- </div>
- )
- }
-
- export default MathComplex
The output will be displayed as below.
Clicking on Add will add value to counter 1.
Clicking on Addition By 5 will update the value to counter 2.
As you can notice in code, the spread operator is used to just denote the update of a single counter variable and append rest of the counter values with it.
So, the benefit of using this approach is that we can use as many variables as we want and, we can keep values in variables need for incrementing/decrementing values without any hardcoding.
Summary
In this article, we have learned about useReducer() hook and how it can be used in React and in how many ways it can be used. You can download the attached source code along with this article. Now in the next article we will go in detail of using useReducer() hook.