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 :)