Effects and essential hooks · Lesson 15 of 21
useReducer
All state changes in one function, with clear names.
When state grows and its changes multiply and scatter across many handlers, useReducer gathers them in one place. Instead of saying "set this value", you say what happened (dispatch({ type: "added" })), and a function called a reducer decides the new state.
function cartReducer(state, action) {
switch (action.type) {
case "added":
return { ...state, items: [...state.items, action.item] }
case "removed":
return { ...state, items: state.items.filter((i) => i.id !== action.id) }
case "couponApplied":
return { ...state, discount: 0.1 }
default:
throw new Error("Unknown action " + action.type)
}
}
function App() {
const [cart, dispatch] = useReducer(cartReducer, { items: [], discount: 0 })
const total = cart.items.reduce((s, i) => s + i.price, 0) * (1 - cart.discount)
return (
<div>
<button onClick={() => dispatch({ type: "added", item: { id: Date.now(), title: "React", price: 600 } })}>Add React</button>
<button onClick={() => dispatch({ type: "couponApplied" })}>Apply coupon</button>
<ul>
{cart.items.map((i) => (
<li key={i.id}>{i.title} <button onClick={() => dispatch({ type: "removed", id: i.id })}>x</button></li>
))}
</ul>
<p>Total: {total} EGP</p>
</div>
)
}Button: dispatch({ type: "added", item })
React calls cartReducer(state, action)
The reducer returns a new state
re-render
Spot the bug
This reducer breaks React's rules. Which line?
Exercise
Finish quizReducer: the answered action carries correct (true/false). If correct, add one to score; either way add one to asked. The checker presses Right twice and Wrong once, so it should show Score: 2 / 3.
Score: 2 / 3 Right Wrong
function quizReducer(state, action) {
return state
}
function App() {
const [s, dispatch] = useReducer(quizReducer, { score: 0, asked: 0 })
return (
<div>
<p>Score: {s.score} / {s.asked}</p>
<button className="ok" onClick={() => dispatch({ type: "answered", correct: true })}>Right</button>
<button className="no" onClick={() => dispatch({ type: "answered", correct: false })}>Wrong</button>
</div>
)
}Learn more from
Played 0 of 2 games
Sign in to save your progress and earn XP.