DEV Community

Cover image for React Hooks - useReducer
Andrew
Andrew

Posted on • Edited on

React Hooks - useReducer

I have a YouTube video where I go into more detail. I explain the reducer function in greater depth there as well.

What is it?

The useReducer hook is great to use if you need to handle more complex state.

If you're familiar with Redux, it's very similar to that, only you'd typically only use it for a component or two.

Complex state

Let's say you're fetching some data, and you want to display:

  • "loading..." while it's fetching
  • the data once you have it
  • or an error if there is one

You'll want all three of these to be in sync with each other. If you get the data, you want to make sure it's not loading and there's no error. If you get an error, it's not loading and there's no data.

This is a good use case for useReducer!

How to use it

We'll have to pass two things into the useReducer hook. A reducer, which we'll use to manage our state; and an initial state to start working off of.

Our initial state will be an object containing three keys: loading, data, and error.

Our reducer will listen for three different action types, and update the state accordingly. Those action types will be fetchDataStart, fetchDataSuccess, and fetchDataFail.

We'll put those in our file, but outside of the component:

//App.js
import React, { useReducer } from 'react';

const initialState = {
  loading: false,
  data: null,
  error: null
}

const reducer = (state, action) => {
  switch (action.type) {
    case 'fetchDataStart':
      return {
        ...state,
        loading: true,
        data: null,
        error: null
      }
    case 'fetchDataSuccess':
      return {
        ...state,
        loading: false,
        data: action.data,
        error: null
      }
    case 'fetchDataFail':
      return {
        ...state,
        loading: false,
        data: null,
        error: 'whoops =/'
      }
    default: return state
   }
}

const App = () => {
  return (
    <h1>App Component</h1>
  )
}
Enter fullscreen mode Exit fullscreen mode

Notice we saved those under the constant variables: reducer and initialState. So we'll pass those into the useReducer hook.

const App = () => {
  useReducer(reducer, initialState);
  return (
    <h1>App Component</h1>
  )
}
Enter fullscreen mode Exit fullscreen mode

The useReducer hook will return two things in an array: the state, and an action dispatcher to update the state.

We'll grab those with array destructuring, similar to state and setState with the useState hook.

const App = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <h1>App Component</h1>
  )
}
Enter fullscreen mode Exit fullscreen mode

Dispatching actions

Our useReducer hook is all setup. Now, let's use it!

We'll create a function for fetching data, and we'll dispatch different actions based on the state of that fetch request.

(Those actions are being checked for in our reducer via the switch statement and our case clauses.)

const App = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const fetchData = () => {
     dispatch({type: 'fetchDataStart'})
     fetch('ourbackend.com/data')
     .then(res => {
        dispatch({
          type: 'fetchDataSuccess',
          data: res.data
        })
     })
     .catch(error => {
        dispatch({type: 'fetchDataFail'})
     })
   }
   return (
      <h1>App Component</h1>
   )
}
Enter fullscreen mode Exit fullscreen mode

Accessing the state

Accessing the state is very easy. useReducer returned that in the array we destructured. We saved it to the constant variable, state.

That state (our initial state and the updated state) is an object. So we'll access the values right in our component like so:

  return (
     <h1>App Component</h1>
     <p>{state.loading}</p>
     <p>{state.data}</p>
     <p>{state.error}</p>
  )
Enter fullscreen mode Exit fullscreen mode

Conclusion

The useReducer hook is extremely helpful when different states depend on each other.

As for bringing in Redux, I'll typically do that if there's complex state for the entire application. If it's only for a component or two, I'll use useReducer.

If you like learning about similar topics, feel free to check out my YouTube and Instagram.

Hope this helped somebody and thanks for reading!

-Andrew

Top comments (23)

Collapse
 
jotsarupsingh profile image
jotsarup-singh

i call it mini version of redux.

Collapse
 
reactifystudio profile image
Reactify

So can I ditch redux and use this stuff alone?

Collapse
 
techcheck profile image
Andrew • Edited

Good question. Redux is great for combining multiple reducers. (and combining all the dispatched actions to work together). It's also good for injecting middleware for developer tools and performing asynchronous tasks (fetch data, etc..) inside actions. I might have to add an edit to the blog 🤔👍.

Thread Thread
 
reactifystudio profile image
Reactify

What others do I need I hear of thunk redux and such.but I don't know much about it. I've used context API alone

Thread Thread
 
reactifystudio profile image
Reactify

I see other stuff like redux thunk. Can you advise me on everything I need for redux. I'll have 100 code days in Frontend (react and Firebase)
.

Collapse
 
jotsarupsingh profile image
jotsarup-singh

@reactifystudio it can be used in small medium size projects but for large application its difficult to manage.

Thread Thread
 
reactifystudio profile image
Reactify

Okay thanks. And which other tools you use in React?.

Collapse
 
techcheck profile image
Andrew

That's how I think of it 😂

Collapse
 
petrtcoi profile image
Petr Tcoi

Is there any naming convention for components with useDispatch from react-redux?

const dispatch = useDispatch()
and
const [state, dispatch] = useReducer(reducer, initialState)

Collapse
 
kleguizamon profile image
Kevin Leguizamon

Hey man, greats tutorial 👍

Collapse
 
techcheck profile image
Andrew

Thanks! 🙏

Collapse
 
devoskar profile image
Oskar Pietrucha

Nice tutorial, thanks! I'm gonna implement it in my projects

Collapse
 
techcheck profile image
Andrew

My pleasure! Awesome to hear!

Collapse
 
techcheck profile image
Andrew

I could see that. Good call

Collapse
 
vanaroth_aya profile image
Vanaroth

Very good post, thank you.

Collapse
 
techcheck profile image
Andrew

Thank you 🙏

Collapse
 
alpinstang profile image
John McDonald

Great article! Hooks are the best thing since functional components in React!

Collapse
 
techcheck profile image
Andrew

Thanks! Agreed!

Collapse
 
ical10 profile image
Husni Rizal

Thanks! Clear and concise, just what I needed.

Collapse
 
techcheck profile image
Andrew

Thanks! 🙏

Collapse
 
dhan46code profile image
dhan46code

Greatt, i like this article

Collapse
 
spyda247 profile image
Babajide Ibiayo

Awesome!!! Thanks. I enjoyed the video so much that I coded each line and then went ahead to build an express API server to fetch random quotes off a mongoDb database running on my laptop.

Collapse
 
techcheck profile image
Andrew

That's so awesome to hear!