useReducer Hook In ReactJS

useReducer hook in reactJS

In this, we will be discussing the useReducer Hook in ReactJS. We will also see the application in fetching data and also its combination with the useContext hook.

Introduction

Before starting this article, we will first discuss hooks. We use hooks to maintain the state of functional components. Hook provides many features like state, context, side effects, and lifecycle methods to the functional component of react. The useReducer hook in Reactjs is one of the hooks in react that helps you to manage a state and re-render the react component whenever a change in state occurs. The only difference is that it is used to handle more complex states, similar to the useState.

Structure of useReducer Hook in Reactjs

The syntax useReducer function is as follows:

const [state, dispatch] = useReducer(reducer, initialState, init);

The useReducer hook takes three arguments, and it returns two values. The first argument is the reducer function. This reducer function is responsible for the updation of the state. The second function is initialState; this is the initial value of the state. The third argument, init, is a function that can be used to return the original state. It is called only once during the rendering process (this argument is optional).

It returns two things: state and dispatch. The state is the current state of the functional component, and dispatch is a function that dispatches actions to the reducer function to update the state.

useReducer hook with useContext

Before using the combination of the useReducer hook with the useContext hook, we need to know why we use this combination. As of now, we know that the useReducer hook is used to handle the state inside the functional component, and the useContext hook is used to pass data from the parent component to the child component. But what if we need to pass states through different components? Yes, by using the combination of the useReducer hook and useContext hook, we can share states through the components, which is referred to as Global State Management.

To understand this, we will be taking an example where three components can simultaneously update a single global state.

Example

In the following example, we will be implementing a simple counter application. To make the application make three different files for three different components (CompA, CompB, and CompC).

App.js

import './App.css';
import React, {useReducer, createContext} from 'react';
import CompA from './CompA';
import CompB from './CompB';
import CompC from './CompC';

const countContext = createContext();

const initialState = 0;
function reducer(state, action){
  switch(action){
    case 'increase':
      return state+1;
    case 'decrease':
      return state-1;
    case 'reset':
      return initialState;
    default:
      return state;
  }
}

function App() 
{
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <countContext.Provider value={{countState: state, countDispatch: dispatch}}>
      <div className="App">
        <h1>Global Value of State: {state}</h1>
          <CompA></CompA>
          <CompB></CompB>
          <CompC></CompC>
      </div>
    </countContext.Provider>
  );
}

export default App;
export {countContext};

CompA

import React, { useContext } from 'react';
import { countContext } from './App';

const CompA = () => {
    const cntContext = useContext(countContext);
    return(
        <div>
            <h2>Component A</h2>
            <button onClick={() => cntContext.countDispatch('increase')}>Increase by 1</button>
        </div>
    );
}

export default CompA;

CompB

import React, { useContext } from 'react';
import { countContext } from './App';

const CompB = () => {
    const cntContext = useContext(countContext);
    return(
        <div>
            <h2>Component B</h2>
            <button onClick={() => cntContext.countDispatch('decrease')}>Decrease by 1</button>
        </div>
    );
}

export default CompB;

CompC

import React, { useContext } from 'react';
import { countContext } from './App';

const CompC = () => {
    const cntContext = useContext(countContext);
    return(
        <div>
            <h2>Component C</h2>
            <button onClick={() => cntContext.countDispatch('reset')}>Reset</button>
        </div>
    );
}

export default CompC;

Output

Explanation

In the above example, we have defined a global state using the useReducer hook. We have also imported three different components, i.e., CompA, CompB, and CompC. The CompA tries to increase the value of the global state by one, whereas the CompB tries to decrease its value by 1. The CompC resets it to the initial state. We are creating a context named countContext in the App.js component that acts as a provider for CompA, CompB, and CompC. 

Now in all three children components, we use the useContext hook. We update the global state by calling the dispatch function using the useContext hook that provides action to the reducer function of the useReducer hook. In this way, we can use the useReducer hook with the useContext hook in react for global state management.

Fetching Data

This is one more interesting application of the useReducer hook in react. The useReducer hook, in combination with the useEffect hook, can be used to fetch data from different APIs. We will be seeing an example where we will be fetching some data from API using the useReducer hook. 

Example

The following is the App.js file which fetches data from this link.

Code

import './App.css';
import React, {useReducer, useEffect} from 'react';
import axios from 'axios';

const initialState = {
  loading: true,
  albums: {},
  errors: '',
}

const reducer = (state, action) => {
  switch(action.status){
    case 'SUCCESSUL_FETCH':
      return {
        loading: false,
        albums: action.info,
        errors: ''
      }
    case 'UNSUCCESSFUL_FETCH':
      return {
        loading: true,
        albums: {},
        errors: 'Error!'
      }
    default:
      return state
  }
}

function randomNumber(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function App() 
{
  const [state, dispatch] = useReducer(reducer, initialState);
  var randomnumber = randomNumber(1, 100);
  useEffect(() => {
    axios.get(`https://jsonplaceholder.typicode.com/albums/${randomnumber}`)
      .then(res => {
          dispatch({status: 'SUCCESSUL_FETCH', info: res.data});
      })
      .catch(err => {
        dispatch({status: 'UNSUCCESSUL_FETCH'});
      })
  }, [])

  return (
      <div className="App">
        <h1>useReducer For Fetching Data</h1>
        {state.loading ? 'Loading' : state.albums.title}
        {state.error ? state.error : null}
      </div>
  );
}

export default App;

Output

Explanation

In the above code, we are using the axios module to fetch the data. We have created an initial state as an object that stores three values: loading, albums, and errors. Then to update the state we have created a reducer function. We are using the useEffect hook because as soon as the axios module fetches the data, we update the state using the reducer function via the dispatch method. The dispatch method sends the status and the data fetched from the API to the reducer function.

Conclusion

  • The useReducer hook is similar to the useState hook. The only difference is that useReducer is an advanced version of useState as it can handle more complex states.
  • We can use useReducer hook with the useContext hook for global state management. That helps different functional components to update the common state simultaneously.
  • To fetch data fro different APIs, we can use the useReducer hook in combination with useEffect hook.
0 Shares:
You May Also Like
hooks in reactjs
Read More

Hooks In ReactJS

Introduction In the further versions of ReactJS, the performance of functional components is greater than class components. So,…