Introduction
In previous article, I have tried to explain the useState
hook. The word reducer
might present a thought about Redux
but don’t worry you don’t have to think about it. I will try to explain what useReducer
is and how to use it.
When it comes for managing complex state logic , useState
might not be a good idea. There comes the idea about useReducer
.
Let’s dive in !!!
UseReducer()
useReducer()
is used for storing and updating states. Basically with reducer you trigger some action to view, those event are listened by reducer who has the logic for storing or updating the state. When the state is updated your component re-render.
Anatomy of useReducer()
The useReducer(reducer, initialState)
hook accepts 2 parameter. The reducer
function as a first parameter and the initial state
as a second parameter. The hook then returns an array of 2 items: the current state and the dispatch function.
useReducer
returns an array of length two, whose first item as current stated and second item is dispatch
functions.
Declaring the useReducer()
Import the useReducer()
package from react
import React, {useReducer} from 'react';
Initialising the useReducer ()
We can initialising useReducer by following way.
const [state, dispatch] = useReducer(reducer, initialState)
Now we will try to decipher what is the meaning state
, dispatch
, reducer
, initialState
these terms.
Let’s create a counter app. With the help of this app I will try to explain the meaning of aforementioned terms.
Initial State
This is the default value of our component’s state when it renders first time.
const initialState = {count: 0}; // At Line 13
Dispatch Function
The dispatch
function is the second items returned from the useReducer
. It accepts and object that represents the type of action we want to perform. It sends an action to reducer
function and reducer
function perform the appropriate job ( update the state) on the basis of received action.
The actions that will be dispatched by our components should always be represented as one object with the type
and payload
key, where type
stands as the identifier of the dispatched action and payload
is the piece of information that this action will add to the state.
onPress={() => {
dispatch({type: 'Decrement', payload: {}});
}}
Reducer Function
The reducer
function accepts two parameters, the current state
& the action object
. So conventionally, the action
is an object with one required property and one optional property:
-
type
is the required property. It tells the reducer what piece of logic it should be using to modify the state. -
payload
is the optional property. It provides additional information to the reducer on how to modify the state.
const reducer = (state, action) => {
switch (action.type) {
case 'Increment':
return {...state, count: state.count + 1};
case 'Decrement':
return {...state, count: state.count - 1};
case 'Reset':
return {...state, count: 0};
default:
return state;
}
};
Basically reducer
accepts a current state, update the state on the basis of action object and return a new state.
Conclusion
We can conclude the useReducer
in one picture.
Let’s note down all the key points regarding the useReducer
-
useReducer
is used for managing complex state. -
useReducer
accepts two argumentreducer
function andinitial state
for initialisation .
useReducer(reducer, initialState)
-
We can initialise
useReducer
lazily by passing theinit
function as a third parameter
useReducer(reducer, initialState,init)
-
useReducer
returns an array, whose first item representcurrent state
and other one isdispatch
function.
const [state, dispatch] = useReducer(reducer, initialState); // state and dispatch is just a naming convention.
We can update the state by calling
dispatch
method. It accepts an object with two parameter. One istype
and other ispayload
for the additional information.The
reducer
function accepts the current state and action object. On the basis ofaction.type
it update the current state and return the new updated state.
Thanks for reading this article. Feel free to add suggestion. You can follow me on Twitter
Top comments (7)
I wouldn’t call it modern JS (btw this thing existed I think 10 years ago, called Object literals), also it’s worse & they are totally different things:
The OP uses switch case which is perfect for this case, since JS will create a jump table which has better performance.
But yours will create object everytime repeatedly.
Nice article!
However I’d like to add some ideas:
Thanks for sharing.
I have stared learning react -native. Before this I was Working as an Android Application developer. Feel free to provide the resources. I love to read them.
By the way whatever you guys are discussing. I love to learn from it.
Thanks again
If you have Java background, I believe you wouldn’t have any problem learning js/ts and react.
Keep moving!
Before laughing, you didn't realize that I'm talking about the object literal vs switch-case, and explaining why your solution is worse?
1) First, it was very clear when I mentioned the main different thing between your solution and the OP's, is the switch vs object literal.
If you're still trying to say the main differences are the arrow function, spread, destructuring,.. things (which OP already used!) … I have nothing to say. It's a useless argument because you will always try to find a non-sense reason. Feel free to laugh anyway.
2)
a) In the OP's solution, there will be a jump table, and it will jump to the correct part to run (destructuring the state, merging with new count value)
b) In your solution, you will always create the object, plus, it will destructure the state + merge the count value 3 times (for Increment, Decrement, and Reset key).
Want to see performance? (Btw if you understand it well, you don't even need to benchmark it lol)
Yours is even worse in the case in which the next state is null, nullish coalescing will make the next state = previous state instead.
Thanks for sharing.