22title : Queueing a Series of State Updates
33---
44
5- ` <Intro> ` {=html}
5+ <Intro >
66
77Setting a state variable will queue another render. But sometimes you
88might want to perform multiple operations on the value before queueing
99the next render. To do this, it helps to understand how React batches
1010state updates.
1111
12- ` </Intro> ` {=html}
12+ </Intro >
1313
14- ` <YouWillLearn> ` {=html}
14+ <YouWillLearn >
1515
1616- What "batching" is and how React uses it to process multiple state
1717 updates
1818- How to apply several updates to the same state variable in a row
1919
20- ` </YouWillLearn> ` {=html}
20+ </YouWillLearn >
2121
2222## React batches state updates {/* react-batches-state-updates* /}
2323
2424You might expect that clicking the "+3" button will increment the
2525counter three times because it calls ` setNumber(number + 1) ` three
2626times:
2727
28- ` <Sandpack> ` {=html}
28+ <Sandpack >
2929
3030``` js
3131import { useState } from ' react' ;
@@ -51,7 +51,7 @@ button { display: inline-block; margin: 10px; font-size: 20px; }
5151h1 { display : inline-block ; margin : 10px ; width : 30px ; text-align : center ; }
5252```
5353
54- ` </Sandpack> ` {=html}
54+ </Sandpack >
5555
5656However, as you might recall from the previous section, [ each render's
5757state values are
@@ -75,7 +75,7 @@ waiter doesn't run to the kitchen at the mention of your first dish!
7575Instead, they let you finish your order, let you make changes to it, and
7676even take orders from other people at the table.
7777
78- ` <Illustration src="/images/docs/illustrations/i_react-batching.png" alt="An elegant cursor at a restaurant places and order multiple times with React, playing the part of the waiter. After she calls setState() multiple times, the waiter writes down the last one she requested as her final order." /> ` {=html}
78+ <Illustration src =" /images/docs/illustrations/i_react-batching.png " alt =" An elegant cursor at a restaurant places and order multiple times with React, playing the part of the waiter. After she calls setState() multiple times, the waiter writes down the last one she requested as her final order. " />
7979
8080This lets you update multiple state variables--even from multiple
8181components--without triggering too many
@@ -103,7 +103,7 @@ the queue, like `setNumber(n => n + 1)`. It is a way to tell React to
103103
104104Try incrementing the counter now:
105105
106- ` <Sandpack> ` {=html}
106+ <Sandpack >
107107
108108``` js
109109import { useState } from ' react' ;
@@ -129,7 +129,7 @@ button { display: inline-block; margin: 10px; font-size: 20px; }
129129h1 { display : inline-block ; margin : 10px ; width : 30px ; text-align : center ; }
130130```
131131
132- ` </Sandpack> ` {=html}
132+ </Sandpack >
133133
134134Here, ` n => n + 1 ` is called an ** updater function.** When you pass it
135135to a state setter:
@@ -161,17 +161,19 @@ to the first updater function as the `n` argument. Then React takes the
161161return value of your previous updater function and passes it to the next
162162updater as ` n ` , and so on:
163163
164- queued update ` n ` returns
165- --------------- ----- -------------
166- ` n => n + 1 ` ` 0 ` ` 0 + 1 = 1 `
167- ` n => n + 1 ` ` 1 ` ` 1 + 1 = 2 `
168- ` n => n + 1 ` ` 2 ` ` 2 + 1 = 3 `
164+ | queued update | ` n ` | returns |
165+ | ---------------| -----| ---------|
166+ | ` n => n + 1 ` | ` 0 ` | ` 0 + 1 = 1 ` |
167+ | ` n => n + 1 ` | ` 1 ` | ` 1 + 1 = 2 ` |
168+ | ` n => n + 1 ` | ` 2 ` | ` 2 + 1 = 3 ` |
169169
170170React stores ` 3 ` as the final result and returns it from ` useState ` .
171171
172172This is why clicking "+3" in the above example correctly increments the
173- value by 3. \# ## What happens if you update state after replacing it
174- {/* what-happens-if-you-update-state-after-replacing-it* /}
173+ value by 3.
174+
175+ ### What happens if you update state after replacing it {/* what-happens-if-you-update-state-after-replacing-it* /}
176+
175177
176178What about this event handler? What do you think ` number ` will be in the
177179next render?
@@ -183,7 +185,7 @@ next render?
183185}}>
184186```
185187
186- ` <Sandpack> ` {=html}
188+ <Sandpack >
187189
188190``` js
189191import { useState } from ' react' ;
@@ -208,7 +210,7 @@ button { display: inline-block; margin: 10px; font-size: 20px; }
208210h1 { display : inline-block ; margin : 10px ; width : 30px ; text-align : center ; }
209211```
210212
211- ` </Sandpack> ` {=html}
213+ </Sandpack >
212214
213215Here's what this event handler tells React to do:
214216
@@ -219,22 +221,20 @@ Here's what this event handler tells React to do:
219221
220222During the next render, React goes through the state queue:
221223
222- queued update ` n ` returns
223- -------------------- -------------- -------------
224- "replace with ` 5 ` " ` 0 ` (unused) ` 5 `
225- ` n => n + 1 ` ` 5 ` ` 5 + 1 = 6 `
224+ | queued update | ` n ` | returns |
225+ | ---------------| -----| ---------|
226+ | "replace with ` 5 ` " | ` 0 ` (unused) | ` 5 ` |
227+ | ` n => n + 1 ` | ` 5 ` | ` 6 ` |
226228
227229React stores ` 6 ` as the final result and returns it from ` useState ` .
228230
229- ``` {=html}
230231<Note >
231- ```
232+
232233You may have noticed that ` setState(5) ` actually works like
233234` setState(n => 5) ` , but ` n ` is unused!
234235
235- ``` {=html}
236236</Note >
237- ```
237+
238238### What happens if you replace state after updating it {/* what-happens-if-you-replace-state-after-updating-it* /}
239239
240240Let's try one more example. What do you think ` number ` will be in the
@@ -248,7 +248,7 @@ next render?
248248}}>
249249```
250250
251- ` <Sandpack> ` {=html}
251+ <Sandpack >
252252
253253``` js
254254import { useState } from ' react' ;
@@ -274,7 +274,7 @@ button { display: inline-block; margin: 10px; font-size: 20px; }
274274h1 { display : inline-block ; margin : 10px ; width : 30px ; text-align : center ; }
275275```
276276
277- ` </Sandpack> ` {=html}
277+ </Sandpack >
278278
279279Here's how React works through these lines of code while executing this
280280event handler:
@@ -287,11 +287,11 @@ event handler:
287287
288288During the next render, React goes through the state queue:
289289
290- queued update ` n ` returns
291- --------------------- -------------- -------------
292- "replace with ` 5 ` " ` 0 ` (unused) ` 5 `
293- ` n => n + 1 ` ` 5 ` ` 5 + 1 = 6 `
294- "replace with ` 42 ` " ` 6 ` (unused) ` 42 `
290+ | queued update | ` n ` | returns |
291+ | ---------------| -----| - --------|
292+ | "replace with ` 5 ` " | ` 0 ` (unused) | ` 5 ` |
293+ | ` n => n + 1 ` | ` 5 ` | ` 6 ` |
294+ | "replace with ` 42 ` " | ` 6 ` (unused) | ` 42 ` |
295295
296296Then React stores ` 42 ` as the final result and returns it from
297297` useState ` .
@@ -326,7 +326,7 @@ If you prefer more verbose code, another common convention is to repeat
326326the full state variable name, like ` setEnabled(enabled => !enabled) ` , or
327327to use a prefix like ` setEnabled(prevEnabled => !prevEnabled) ` .
328328
329- ` <Recap> ` {=html}
329+ <Recap >
330330
331331- Setting state does not change the variable in the existing render,
332332 but it requests a new render.
@@ -335,9 +335,9 @@ to use a prefix like `setEnabled(prevEnabled => !prevEnabled)`.
335335- To update some state multiple times in one event, you can use
336336 ` setNumber(n => n + 1) ` updater function.
337337
338- ` </Recap> ` {=html}
338+ </Recap >
339339
340- ` <Challenges> ` {=html}
340+ <Challenges >
341341
342342#### Fix a request counter {/* fix-a-request-counter* /}
343343
@@ -353,7 +353,7 @@ if you click fast twice, both counters seem to behave unpredictably.
353353
354354Why does this happen? Fix both counters.
355355
356- ` <Sandpack> ` {=html}
356+ <Sandpack >
357357
358358``` js
359359import { useState } from ' react' ;
@@ -391,7 +391,7 @@ function delay(ms) {
391391}
392392```
393393
394- ` </Sandpack> ` {=html}
394+ </Sandpack >
395395
396396> ** Why this bug happens**
397397>
@@ -406,7 +406,7 @@ function delay(ms) {
406406> (for example, ` setPending(p => p + 1) ` ) ensures that each update is
407407> applied to the most recent state value in the queue.
408408
409- ` <Solution> ` {=html}
409+ <Solution >
410410
411411Inside the ` handleClick ` event handler, the values of ` pending ` and
412412` completed ` correspond to what they were at the time of the click event.
@@ -415,7 +415,7 @@ becomes `setPending(-1)`, which is wrong. Since you want to *increment*
415415or * decrement* the counters, rather than set them to a concrete value
416416determined during the click, you can instead pass the updater functions:
417417
418- ` <Sandpack> ` {=html}
418+ <Sandpack >
419419
420420``` js
421421import { useState } from ' react' ;
@@ -453,13 +453,13 @@ function delay(ms) {
453453}
454454```
455455
456- ` </Sandpack> ` {=html}
456+ </Sandpack >
457457
458458This ensures that when you increment or decrement a counter, you do it
459459in relation to its * latest* state rather than what the state was at the
460460time of the click.
461461
462- ` </Solution> ` {=html}
462+ </Solution >
463463
464464#### Implement the state queue yourself {/* implement-the-state-queue-yourself* /}
465465
@@ -480,7 +480,7 @@ added.
480480Your task is to return the final state, just like the tables on this
481481page show!
482482
483- ` <Hint> ` {=html}
483+ <Hint >
484484
485485If you're feeling stuck, start with this code structure:
486486
@@ -502,16 +502,19 @@ export function getFinalState(baseState, queue) {
502502
503503Fill out the missing lines!
504504
505- ` </Hint> ` {=html}
505+ </Hint >
506506
507- ` <Sandpack> ` {=html}
507+ <Sandpack >
508508
509- \`\`\` js src/processQueue.js active export function
510- getFinalState(baseState, queue) { let finalState = baseState;
509+ ``` js src/processQueue.js active
510+ export function getFinalState (baseState , queue ) {
511+ let finalState = baseState;
511512
512- // TODO: do something with the queue...
513+ // TODO: do something with the queue...
513514
514- return finalState; }
515+ return finalState;
516+ }
517+ ```
515518
516519
517520 ```js src/App.js
@@ -590,23 +593,32 @@ return finalState; }
590593 );
591594 }
592595
593- ` </Sandpack> ` {=html}
596+ </Sandpack >
594597
595- ` <Solution> ` {=html}
598+ <Solution >
596599
597600This is the exact algorithm described on this page that React uses to
598601calculate the final state:
599602
600- ` <Sandpack> ` {=html}
603+ <Sandpack >
601604
602- \`\`\` js src/processQueue.js active export function
603- getFinalState(baseState, queue) { let finalState = baseState;
605+ ``` js src/processQueue.js active
606+ export function getFinalState (baseState , queue ) {
607+ let finalState = baseState;
604608
605- for (let update of queue) { if (typeof update === 'function') { // Apply
606- the updater function. finalState = update(finalState); } else { //
607- Replace the next state. finalState = update; } }
609+ for (let update of queue) {
610+ if (typeof update === ' function' ) {
611+ // Apply the updater function.
612+ finalState = update (finalState);
613+ } else {
614+ // Replace the next state.
615+ finalState = update;
616+ }
617+ }
608618
609- return finalState; }
619+ return finalState;
620+ }
621+ ```
610622
611623
612624 ```js src/App.js
@@ -685,10 +697,10 @@ return finalState; }
685697 );
686698 }
687699
688- ` </Sandpack> ` {=html}
700+ </Sandpack >
689701
690702Now you know how this part of React works!
691703
692- ` </Solution> ` {=html}
704+ </Solution >
693705
694- ` </Challenges> ` {=html}
706+ </Challenges >
0 commit comments