I was having trouble to understand useReducer
because I don't have Redux background. So I wrote this article to explain it to myself, and I hope it can help you as well.
Learn useState
first
If you know how useState
works, then you can skip this section, and I am going to compare useReducer
to useState
.
useState
example (reactjs.org)
const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
const [count, setCount] = useState(0);
-
useState(0)
: It passes the initial state (in this case, it is 0), and returns an array with 2 elements -count
andsetCount
. -
count
: new state -
setCount
: the function that uses to change the state value. It is likethis.setState()
in class based component.
Compare to useReducer
useReducer
is used for complicated state
situation.
For example, I want to add one more button to decrease counter.
Here is the code by using useState
useState
example (reactjs.org)
const [count, setCount] = useState(0); return ( <div> {count} <button onClick={() => setCount(count + 1)}> + </button> <button onClick={() => setCount(count - 1)}> - </button> </div> ); }
We are going to move count+1
and count -1
to a FUNCTION
by using useReducer
const [count, setCount] = useReducer(FUNCTION, {count: 0})
In useReducer
, we call count
as state
, setCount
as dispatch
, and FUNCTION
is reducer
So it looks like this -
const [state, dispatch] = useReducer(reducer, {count: 0})
MDN explains pretty well what is Array.prototype.reduce()
is. It may help you to understand what is the reducer funciton in useReducer
.
Next, we are going to write the reducer function
reducer function
passes 2 parameters
function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } }
state
: the current state
action
: if I want to change state, then I call dispatch function. In this case, the first element is type
, refer to action.type
.
For example, I call dispatch({type: 'increment'})
, then count
will be + 1.
<button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button>
Full codes -
function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, {count: 0}); return ( {state.count} <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); }
Hope it will help you! ❤️
Top comments (1)
Wow, useReducer definitely looks cleaner than writing separate handlers for different state updates. Thanks for sharing :)