Skip to content

Commit 5071284

Browse files
committed
Clarify reducer state updater
1 parent 6be2b02 commit 5071284

1 file changed

Lines changed: 14 additions & 6 deletions

File tree

src/content/learn/extracting-state-logic-into-a-reducer.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,7 +2439,7 @@ textarea {
24392439
24402440
<Solution>
24412441
2442-
Dispatching an action calls a reducer with the current state and the action, and stores the result as the next state. This is what it looks like in code:
2442+
To implement this Hook, define a `dispatch` function. It receives an action and tells React how to calculate the next state from the previous state. This is what it looks like in code:
24432443
24442444
<Sandpack>
24452445
@@ -2527,8 +2527,7 @@ export function useReducer(reducer, initialState) {
25272527
const [state, setState] = useState(initialState);
25282528

25292529
function dispatch(action) {
2530-
const nextState = reducer(state, action);
2531-
setState(nextState);
2530+
setState((prevState) => reducer(prevState, action));
25322531
}
25332532

25342533
return [state, dispatch];
@@ -2614,15 +2613,24 @@ textarea {
26142613
26152614
</Sandpack>
26162615
2617-
Though it doesn't matter in most cases, a slightly more accurate implementation looks like this:
2616+
Because the reducer calculates new state from previous state, pass an updater function to `setState` whenever possible. React will call it with the previous state. Naming its parameter `prevState` makes this clear:
26182617
26192618
```js
26202619
function dispatch(action) {
2621-
setState((s) => reducer(s, action));
2620+
setState((prevState) => reducer(prevState, action));
26222621
}
26232622
```
26242623
2625-
This is because the dispatched actions are queued until the next render, [similar to the updater functions.](/learn/queueing-a-series-of-state-updates)
2624+
You might instead calculate the next state directly from `state`:
2625+
2626+
```js
2627+
function dispatch(action) {
2628+
const nextState = reducer(state, action);
2629+
setState(nextState);
2630+
}
2631+
```
2632+
2633+
This works if you dispatch only one action before React renders again. However, React can batch multiple updates. In that case, every call to `dispatch` reads the same `state` value from the current render, so later actions can overwrite the result of earlier ones. Passing an updater function lets React apply each queued action to the state produced by the previous action, [similar to updater functions.](/learn/queueing-a-series-of-state-updates)
26262634
26272635
</Solution>
26282636

0 commit comments

Comments
 (0)