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>
)
}
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>
)
}
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>
)
}
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>
)
}
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>
)
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)
i call it mini version of redux.
So can I ditch redux and use this stuff alone?
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 π€π.
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
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)
.
@reactifystudio it can be used in small medium size projects but for large application its difficult to manage.
Okay thanks. And which other tools you use in React?.
That's how I think of it π
I could see that. Good call
Very good post, thank you.
Thank you π
Is there any naming convention for components with useDispatch from react-redux?
const dispatch = useDispatch()
and
const [state, dispatch] = useReducer(reducer, initialState)
Thanks! Clear and concise, just what I needed.
Thanks! π
Great article! Hooks are the best thing since functional components in React!
Thanks! Agreed!
Hey man, greats tutorial π
Thanks! π
Nice tutorial, thanks! I'm gonna implement it in my projects
My pleasure! Awesome to hear!
Greatt, i like this article
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.
That's so awesome to hear!