| title | state ์ ๋ฐ์ดํธ ํ |
|---|
state ๋ณ์๋ฅผ ์ค์ ํ๋ฉด ๋ค์ ๋ ๋๋ง์ด ํ์ ๋ค์ด๊ฐ๋๋ค. ๊ทธ๋ฌ๋ ๋์ ๋ฐ๋ผ ๋ค์ ๋ ๋๋ง์ ํ์ ๋ฃ๊ธฐ ์ ์, ๊ฐ์ ๋ํด ์ฌ๋ฌ ์์ ์ ์ํํ๊ณ ์ถ์ ๋๋ ์์ต๋๋ค. ์ด๋ฅผ ์ํด์๋ React๊ฐ state ์ ๋ฐ์ดํธ๋ฅผ ์ด๋ป๊ฒ ๋ฐฐ์นํ๋ฉด ์ข์์ง ์ดํดํ๋ ๊ฒ์ด ๋์์ด ๋ฉ๋๋ค.
- "batching"์ด๋ ๋ฌด์์ด๋ฉฐ React๊ฐ ์ฌ๋ฌ state ์ ๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ
- ๋์ผํ state ๋ณ์์์ ์ฌ๋ฌ ์ ๋ฐ์ดํธ๋ฅผ ์ฐ์์ผ๋ก ์ ์ฉํ๋ ๋ฐฉ๋ฒ
setNumber(number + 1)๋ฅผ ์ธ ๋ฒ ํธ์ถํ๋ฏ๋ก "+3" ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ธ ๋ฒ ์ฆ๊ฐํ ๊ฒ์ผ๋ก ์์ํ ์ ์์ต๋๋ค.
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>+3</button>
</>
)
}button { display: inline-block; margin: 10px; font-size: 20px; }
h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }์ด์ ์ธ์
์์ ๊ธฐ์ตํ ์ ์๋ฏ์ด ๊ฐ ๋ ๋๋ง์ state ๊ฐ์ ๊ณ ์ ๋์ด ์์ผ๋ฏ๋ก, ์ฒซ ๋ฒ์งธ ๋ ๋๋ง์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ number ๊ฐ์ setNumber(1)์ ๋ช ๋ฒ ํธ์ถํ๋ ํญ์ 0์
๋๋ค.
setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);ํ์ง๋ง ์ฌ๊ธฐ์๋ ํ๊ฐ์ง ์์ธ์ด ๋ ์์ต๋๋ค. React๋ state ์
๋ฐ์ดํธ๋ฅผ ํ๊ธฐ ์ ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋ชจ๋ ์ฝ๋๊ฐ ์คํ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ด ๋๋ฌธ์ ๋ฆฌ๋ ๋๋ง์ ๋ชจ๋ setNumber() ํธ์ถ์ด ์๋ฃ๋ ์ดํ์๋ง ์ผ์ด๋ฉ๋๋ค.
์ด๋ ์์์ ์์ ์ฃผ๋ฌธ๋ฐ๋ ์จ์ดํฐ๋ฅผ ์๊ฐํด ๋ณผ ์ ์์ต๋๋ค. ์จ์ดํฐ๋ ์ฒซ ๋ฒ์งธ ์๋ฆฌ๋ฅผ ๋งํ์๋ง์ ์ฃผ๋ฐฉ์ผ๋ก ๋ฌ๋ ค๊ฐ์ง ์์ต๋๋ค! ๋์ ์ฃผ๋ฌธ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์ฃผ๋ฌธ์ ๋ณ๊ฒฝํ๊ณ , ์ฌ์ง์ด ํ ์ด๋ธ์ ์๋ ๋ค๋ฅธ ์ฌ๋์ ์ฃผ๋ฌธ๋ ๋ฐ์ต๋๋ค.
์ด๋ ๊ฒ ํ๋ฉด ๋๋ฌด ๋ง์ ๋ฆฌ๋ ๋๋ง์ด ๋ฐ์ํ์ง ์๊ณ ๋ ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๋์จ ๋ค์์ state ๋ณ์๋ฅผ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค. ํ์ง๋ง ์ด๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๊ทธ ์์ ์๋ ์ฝ๋๊ฐ ์๋ฃ๋ ๋๊น์ง UI๊ฐ ์ ๋ฐ์ดํธ๋์ง ์๋๋ค๋ ์๋ฏธ์ด๊ธฐ๋ ํฉ๋๋ค. batching๋ผ๊ณ ๋ ํ๋ ์ด ๋์์ React ์ฑ์ ํจ์ฌ ๋น ๋ฅด๊ฒ ์คํํ ์ ์๊ฒ ํด์ค๋๋ค. ๋ํ ์ผ๋ถ ๋ณ์๋ง ์ ๋ฐ์ดํธ๋ "๋ฐ์ฏค ์์ฑ๋" ํผ๋์ค๋ฌ์ด ๋ ๋๋ง์ ์ฒ๋ฆฌํ์ง ์์๋ ๋ฉ๋๋ค.
React๋ ํด๋ฆญ๊ณผ ๊ฐ์ ์ฌ๋ฌ ์๋์ ์ธ ์ด๋ฒคํธ์ ๋ํด batch๋ฅผ ์ํํ์ง ์์ผ๋ฉฐ, ๊ฐ ํด๋ฆญ์ ๊ฐ๋ณ์ ์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. React๋ ์์ ํ ๊ฒฝ์ฐ์๋ง batch๋ฅผ ์ํํ๋ ์์ฌํ์ธ์. ์๋ฅผ ๋ค์ด ์ฒซ ๋ฒ์งธ ๋ฒํผ ํด๋ฆญ์ผ๋ก ์์์ด ๋นํ์ฑํ๋๋ฉด ๋ ๋ฒ์งธ ํด๋ฆญ์ผ๋ก ์์์ด ๋ค์ ์ ์ถ๋์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
๋ค์ ๋ ๋๋ง ์ ์ ๋์ผํ state ๋ณ์๋ฅผ ์ฌ๋ฌ ๋ฒ ์ ๋ฐ์ดํธํ๊ธฐ {/updating-the-same-state-multiple-times-before-the-next-render/}
ํํ ์ฌ๋ก๋ ์๋์ง๋ง, ๋ค์ ๋ ๋๋ง ์ ์ ๋์ผํ state ๋ณ์๋ฅผ ์ฌ๋ฌ ๋ฒ ์
๋ฐ์ดํธ ํ๊ณ ์ถ๋ค๋ฉด setNumber(number + 1) ์ ๊ฐ์ ๋ค์ state ๊ฐ์ ์ ๋ฌํ๋ ๋์ , setNumber(n => n + 1) ์ ๊ฐ์ด ์ด์ ํ์ state๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ state๋ฅผ ๊ณ์ฐํ๋ ํจ์๋ฅผ ์ ๋ฌํ ์ ์์ต๋๋ค. ์ด๋ ๋จ์ํ state ๊ฐ์ ๋์ฒดํ๋ ๊ฒ์ด ์๋๋ผ React์ "state ๊ฐ์ผ๋ก ๋ฌด์ธ๊ฐ๋ฅผ ํ๋ผ"๊ณ ์ง์ํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
์ด์ ์นด์ดํฐ๋ฅผ ์ฆ๊ฐ์์ผ ๋ณด์ธ์.
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);
}}>+3</button>
</>
)
}button { display: inline-block; margin: 10px; font-size: 20px; }
h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }์ฌ๊ธฐ์ n => n + 1 ์ ์
๋ฐ์ดํฐ ํจ์(updater function)๋ผ๊ณ ๋ถ๋ฆ
๋๋ค. ์ด๋ฅผ state ์ค์ ์ ํจ์์ ์ ๋ฌ ํ ๋,
- React๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋ค๋ฅธ ์ฝ๋๊ฐ ๋ชจ๋ ์คํ๋ ํ์ ์ด ํจ์๊ฐ ์ฒ๋ฆฌ๋๋๋ก ํ์ ๋ฃ์ต๋๋ค.
- ๋ค์ ๋ ๋๋ง ์ค์ React๋ ํ๋ฅผ ์ํํ์ฌ ์ต์ข ์ ๋ฐ์ดํธ๋ state๋ฅผ ์ ๊ณตํฉ๋๋ค.
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);React๊ฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ํํ๋ ๋์ ์ฌ๋ฌ ์ฝ๋๋ฅผ ํตํด ์๋ํ๋ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
setNumber(n => n + 1):n => n + 1ํจ์๋ฅผ ํ์ ์ถ๊ฐํฉ๋๋ค.setNumber(n => n + 1):n => n + 1ํจ์๋ฅผ ํ์ ์ถ๊ฐํฉ๋๋ค.setNumber(n => n + 1):n => n + 1ํจ์๋ฅผ ํ์ ์ถ๊ฐํฉ๋๋ค.
๋ค์ ๋ ๋๋ง ์ค์ useState ๋ฅผ ํธ์ถํ๋ฉด React๋ ํ๋ฅผ ์ํํฉ๋๋ค. ์ด์ number state๋ 0์ด์์ผ๋ฏ๋ก React๋ ์ด๋ฅผ ์ฒซ ๋ฒ์งธ ์
๋ฐ์ดํฐ ํจ์์ n ์ธ์๋ก ์ ๋ฌํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ React๋ ์ด์ ์
๋ฐ์ดํฐ ํจ์์ ๋ฐํ ๊ฐ์ ๊ฐ์ ธ์์ ๋ค์ ์
๋ฐ์ดํฐ ํจ์์ n์ผ๋ก ์ ๋ฌํ๋ ์์ผ๋ก ๋ฐ๋ณตํฉ๋๋ค.
| queued update | n |
returns |
|---|---|---|
n => n + 1 |
0 |
0 + 1 = 1 |
n => n + 1 |
1 |
1 + 1 = 2 |
n => n + 1 |
2 |
2 + 1 = 3 |
React๋ 3์ ์ต์ข
๊ฒฐ๊ณผ๋ก ์ ์ฅํ๊ณ useState์์ ๋ฐํํฉ๋๋ค.
์ด๊ฒ์ด ์ ์์ "+3"์ ํด๋ฆญํ๋ฉด ๊ฐ์ด 3์ฉ ์ฌ๋ฐ๋ฅด๊ฒ ์ฆ๊ฐํ๋ ์ด์ ์ ๋๋ค.
state๋ฅผ ๊ต์ฒดํ ํ ์ ๋ฐ์ดํธํ๋ฉด ์ด๋ป๊ฒ ๋๋์? {/what-happens-if-you-update-state-after-replacing-it/}
์ด ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ์ด๋จ๊น์? ๋ค์ ๋ ๋๋ง์์ number๊ฐ ์ด๋ป๊ฒ ๋ ๊น์?
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
}}>import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
}}>Increase the number</button>
</>
)
}button { display: inline-block; margin: 10px; font-size: 20px; }
h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }์ด ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ React์ ์ง์ํ๋ ์์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
setNumber(number + 5):number๋0์ด๋ฏ๋กsetNumber(0 + 5)์ ๋๋ค. React๋ ํ์ "5๋ก ๋ฐ๊พธ๊ธฐ" ๋ฅผ ์ถ๊ฐํฉ๋๋ค.setNumber(n => n + 1):n => n + 1๋ ์ ๋ฐ์ดํฐ ํจ์์ ๋๋ค. React๋ ํด๋น ํจ์๋ฅผ ํ์ ์ถ๊ฐํฉ๋๋ค.
๋ค์ ๋ ๋๋งํ๋ ๋์ React๋ state ํ๋ฅผ ์ํํฉ๋๋ค.
| queued update | n |
returns |
|---|---|---|
"replace with 5" |
0 (unused) |
5 |
n => n + 1 |
5 |
5 + 1 = 6 |
React๋ 6์ ์ต์ข
๊ฒฐ๊ณผ๋ก ์ ์ฅํ๊ณ useState์์ ๋ฐํํฉ๋๋ค.
setState(5)๊ฐ ์ค์ ๋ก๋ setState(n => 5) ์ฒ๋ผ ๋์ํ์ง๋ง n์ด ์ฌ์ฉ๋์ง ์๋๋ค๋ ๊ฒ์ ๋์น์ฑ์
จ์ ๊ฒ์
๋๋ค!
์ ๋ฐ์ดํธ ํ state๋ฅผ ๋ฐ๊พธ๋ฉด ์ด๋ป๊ฒ ๋๋์? {/what-happens-if-you-replace-state-after-updating-it/}
ํ ๊ฐ์ง ์๋ฅผ ๋ ๋ค์ด๋ณด๊ฒ ์ต๋๋ค. ๋ค์ ๋ ๋๋ง์์ number๊ฐ ์ด๋ป๊ฒ ๋ ๊น์?
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
setNumber(42);
}}>import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
setNumber(42);
}}>Increase the number</button>
</>
)
}button { display: inline-block; margin: 10px; font-size: 20px; }
h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }์ด ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์คํํ๋ ๋์ React๊ฐ ์ด ์ฝ๋๋ฅผ ํตํด ์๋ํ๋ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
setNumber(number + 5):number๋0์ด๋ฏ๋กsetNumber(0 + 5)์ ๋๋ค. React๋ "5๋ก ๋ฐ๊พธ๊ธฐ" ๋ฅผ ํ์ ์ถ๊ฐํฉ๋๋ค.setNumber(n => n + 1):n => n + 1๋ ์ ๋ฐ์ดํฐ ํจ์์ ๋๋ค. React๋ ์ด ํจ์๋ฅผ ํ์ ์ถ๊ฐํฉ๋๋ค.setNumber(42): React๋ "42๋ก ๋ฐ๊พธ๊ธฐ" ๋ฅผ ํ์ ์ถ๊ฐํฉ๋๋ค.
๋ค์ ๋ ๋๋งํ๋ ๋์, React๋ state ํ๋ฅผ ์ํํฉ๋๋ค.
| queued update | n |
returns |
|---|---|---|
"replace with 5" |
0 (unused) |
5 |
n => n + 1 |
5 |
5 + 1 = 6 |
"replace with 42" |
6 (unused) |
42 |
๊ทธ๋ฐ ๋ค์ React๋ 42๋ฅผ ์ต์ข
๊ฒฐ๊ณผ๋ก ์ ์ฅํ๊ณ useState์์ ๋ฐํํฉ๋๋ค.
์์ฝํ์๋ฉด, setNumber state ์ค์ ์ ํจ์์ ์ ๋ฌํ ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ์ด ์๊ฐํ ์ ์์ต๋๋ค:
- ์
๋ฐ์ดํฐ ํจ์ (์.
n => n + 1) ๊ฐ ํ์ ์ถ๊ฐ๋ฉ๋๋ค. - ๋ค๋ฅธ ๊ฐ (์. ์ซ์
5) ์ ํ์ "5๋ก ๋ฐ๊พธ๊ธฐ"๋ฅผ ์ถ๊ฐํ๋ฉฐ, ์ด๋ฏธ ํ์ ๋๊ธฐ ์ค์ธ ํญ๋ชฉ์ ๋ฌด์ํฉ๋๋ค.
์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์๋ฃ๋๋ฉด React๋ ๋ฆฌ๋ ๋๋ง์ ์คํํฉ๋๋ค. ๋ฆฌ๋ ๋๋งํ๋ ๋์ React๋ ํ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ์ ๋ฐ์ดํฐ ํจ์๋ ๋ ๋๋ง ์ค์ ์คํ๋๋ฏ๋ก, ์ ๋ฐ์ดํฐ ํจ์๋ ์์ํด์ผ ํ๋ฉฐ ๊ฒฐ๊ณผ๋ง ๋ฐํ ํด์ผ ํฉ๋๋ค. ์ ๋ฐ์ดํฐ ํจ์ ๋ด๋ถ์์ state๋ฅผ ๋ณ๊ฒฝํ๊ฑฐ๋ ๋ค๋ฅธ ์ฌ์ด๋ ์ดํฉํธ๋ฅผ ์คํํ๋ ค๊ณ ํ์ง ๋ง์ธ์. Strict ๋ชจ๋์์ React๋ ๊ฐ ์ ๋ฐ์ดํฐ ํจ์๋ฅผ ๋ ๋ฒ ์คํ(๋ ๋ฒ์งธ ๊ฒฐ๊ณผ๋ ๋ฒ๋ฆผ)ํ์ฌ ์ค์๋ฅผ ์ฐพ์ ์ ์๋๋ก ๋์์ค๋๋ค.
์ ๋ฐ์ดํฐ ํจ์ ์ธ์์ ์ด๋ฆ์ ํด๋น state ๋ณ์์ ์ฒซ ๊ธ์๋ก ์ง์ ํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ ๋๋ค.
setEnabled(e => !e);
setLastName(ln => ln.reverse());
setFriendCount(fc => fc * 2);์ข ๋ ์์ธํ ์ฝ๋๋ฅผ ์ ํธํ๋ ๊ฒฝ์ฐ setEnabled(enabled => !enabled)์ ๊ฐ์ด ์ ์ฒด state ๋ณ์ ์ด๋ฆ์ ๋ฐ๋ณตํ๊ฑฐ๋, setEnabled(prevEnabled => !prevEnabled)์ ๊ฐ์ ์ ๋์ฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋๋ฆฌ ์ฌ์ฉ๋๋ ๊ท์น์
๋๋ค.
- state๋ฅผ ์ค์ ํ๋๋ผ๋ ๊ธฐ์กด ๋ ๋๋ง์ ๋ณ์๋ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉฐ, ๋์ ์๋ก์ด ๋ ๋๋ง์ ์์ฒญํฉ๋๋ค.
- React๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์คํ์ ๋ง์น ํ state ์ ๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ์ด๋ฅผ batching ์ด๋ผ๊ณ ํฉ๋๋ค.
- ํ๋์ ์ด๋ฒคํธ์์ ์ผ๋ถ state๋ฅผ ์ฌ๋ฌ ๋ฒ ์
๋ฐ์ดํธํ๋ ค๋ฉด
setNumber(n => n + 1)์ ๋ฐ์ดํฐ ํจ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฌ์ฉ์๊ฐ ๋์์ ์ฌ๋ฌ ๊ฐ์ ๋ฏธ์ ํ์ ์ฃผ๋ฌธํ ์ ์๋ ์์ ์ผํ๋ชฐ ์ฑ์์ ์์ ํ๊ณ ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ "Buy" ๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค "Pending" ์นด์ดํฐ๊ฐ 1์ฉ ์ฆ๊ฐํด์ผ ํฉ๋๋ค. 3์ด ํ์๋ "Pending" ์นด์ดํฐ๊ฐ ๊ฐ์ํ๊ณ "Completed" ์นด์ดํฐ๊ฐ ์ฆ๊ฐํด์ผ ํฉ๋๋ค.
๊ทธ๋ฐ๋ฐ "Pending" ์นด์ดํฐ๊ฐ ์๋๋๋ก ์๋ํ์ง ์๊ณ ์์ต๋๋ค. "Buy"๋ฅผ ๋๋ฅด๋ฉด -1๋ก ๊ฐ์ํฉ๋๋ค(๊ทธ๋ด ์ ์์ต๋๋ค!). ๊ทธ๋ฆฌ๊ณ ๋น ๋ฅด๊ฒ ๋ ๋ฒ ํด๋ฆญํ๋ฉด ๋ ์นด์ดํฐ๊ฐ ๋ชจ๋ ์์ธกํ ์ ์๊ฒ ์๋ํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ ์ด๋ฐ ์ผ์ด ๋ฐ์ํ ๊น์? ๋ ์นด์ดํฐ๋ฅผ ๋ชจ๋ ์์ ํ์ธ์.
import { useState } from 'react';
export default function RequestTracker() {
const [pending, setPending] = useState(0);
const [completed, setCompleted] = useState(0);
async function handleClick() {
setPending(pending + 1);
await delay(3000);
setPending(pending - 1);
setCompleted(completed + 1);
}
return (
<>
<h3>
Pending: {pending}
</h3>
<h3>
Completed: {completed}
</h3>
<button onClick={handleClick}>
Buy
</button>
</>
);
}
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}handleClick ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ด๋ถ์์ Pending๊ณผ Completed์ ๊ฐ์ ํด๋ฆญ ์ด๋ฒคํธ ๋น์์ ๊ฐ๊ณผ ์ผ์นํฉ๋๋ค. ์ฒซ ๋ฒ์งธ ๋ ๋๋ง์ ๊ฒฝ์ฐ, Pending์ด 0์ด์์ผ๋ฏ๋ก setPending(pending - 1)๋ setPending(-1) ๋๋๋ฐ, ์ด๋ ์๋ชป๋ ๊ฒ์
๋๋ค. ํด๋ฆญ ์ค์ ๊ฒฐ์ ๋ ๊ตฌ์ฒด์ ์ธ ๊ฐ์ผ๋ก ์นด์ดํฐ๋ฅผ ์ค์ ํ๋ ๋์ ์นด์ดํฐ๋ฅผ ์ฆ๊ฐ ๋๋ ๊ฐ์ํ๊ณ ์ถ์ผ๋ฏ๋ก ๋์ ์
๋ฐ์ดํฐ ํจ์๋ฅผ ์ ๋ฌํ ์ ์์ต๋๋ค.
import { useState } from 'react';
export default function RequestTracker() {
const [pending, setPending] = useState(0);
const [completed, setCompleted] = useState(0);
async function handleClick() {
setPending(p => p + 1);
await delay(3000);
setPending(p => p - 1);
setCompleted(c => c + 1);
}
return (
<>
<h3>
Pending: {pending}
</h3>
<h3>
Completed: {completed}
</h3>
<button onClick={handleClick}>
Buy
</button>
</>
);
}
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}์ด๋ ๊ฒ ํ๋ฉด ์นด์ดํฐ๋ฅผ ๋๋ฆฌ๊ฑฐ๋ ์ค์ผ ๋ ํด๋ฆญ ๋น์์ state๊ฐ ์๋๋ผ ์ต์ state์ ๊ด๋ จํ์ฌ ์นด์ดํฐ๋ฅผ ๋๋ฆฌ๊ฑฐ๋ ์ค์ผ ์ ์์ต๋๋ค.
์ด๋ฒ ๋์ ๊ณผ์ ์์๋ React์ ์์ ๋ถ๋ถ์ ์ฒ์๋ถํฐ ๋ค์ ๊ตฌํํ๊ฒ ๋ฉ๋๋ค! ์๊ฐ๋ณด๋ค ์ด๋ ต์ง ์์ต๋๋ค.
์๋๋ฐ์ค ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์คํฌ๋กค ํ์ธ์. 4๊ฐ์ ํ
์คํธ ์ผ์ด์ค๊ฐ ํ์๋๋ ๊ฒ์ ํ์ธํ์ธ์. ์ด ํ์ด์ง์ ์๋ถ๋ถ์์ ๋ณด์๋ ์์์ ์ผ์นํฉ๋๋ค. ์ฌ๋ฌ๋ถ์ ์๋ฌด๋ ๊ฐ ์ผ์ด์ค์ ๋ํด ์ฌ๋ฐ๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋๋ก getFinalState ํจ์๋ฅผ ๊ตฌํํ๋ ๊ฒ์
๋๋ค. ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํํ๋ฉด ๋ค ๊ฐ์ง ํ
์คํธ๋ฅผ ๋ชจ๋ ํต๊ณผํ ๊ฒ์
๋๋ค.
๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ๊ฒ ๋ฉ๋๋ค. baseState๋ ์ด๊ธฐ state(์: 0)์ด๊ณ , queue๋ ์ซ์(์: 5)์ ์
๋ฐ์ดํฐ ํจ์(์: n => n + 1)๊ฐ ์ถ๊ฐ๋, ์์๋๋ก ์์ฌ ์๋ ๋ฐฐ์ด์
๋๋ค.
์ฌ๋ฌ๋ถ์ ์๋ฌด๋ ์ด ํ์ด์ง์ ํ์ ํ์๋ ๊ฒ์ฒ๋ผ ์ต์ข state๋ฅผ ๋ฐํํ๋ ๊ฒ์ ๋๋ค!
๋ง๋งํ ๋๋์ด ๋ ๋ค๋ฉด ๋ค์ ์ฝ๋ ๊ตฌ์กฐ๋ก ์์ํด ๋ณด์ธ์.
export function getFinalState(baseState, queue) {
let finalState = baseState;
for (let update of queue) {
if (typeof update === 'function') {
// TODO: apply the updater function
} else {
// TODO: replace the state
}
}
return finalState;
}๋น์นธ์ ์ฑ์์ฃผ์ธ์!
export function getFinalState(baseState, queue) {
let finalState = baseState;
// TODO: do something with the queue...
return finalState;
}import { getFinalState } from './processQueue.js';
function increment(n) {
return n + 1;
}
increment.toString = () => 'n => n+1';
export default function App() {
return (
<>
<TestCase
baseState={0}
queue={[1, 1, 1]}
expected={1}
/>
<hr />
<TestCase
baseState={0}
queue={[
increment,
increment,
increment
]}
expected={3}
/>
<hr />
<TestCase
baseState={0}
queue={[
5,
increment,
]}
expected={6}
/>
<hr />
<TestCase
baseState={0}
queue={[
5,
increment,
42,
]}
expected={42}
/>
</>
);
}
function TestCase({
baseState,
queue,
expected
}) {
const actual = getFinalState(baseState, queue);
return (
<>
<p>Base state: <b>{baseState}</b></p>
<p>Queue: <b>[{queue.join(', ')}]</b></p>
<p>Expected result: <b>{expected}</b></p>
<p style={{
color: actual === expected ?
'green' :
'red'
}}>
Your result: <b>{actual}</b>
{' '}
({actual === expected ?
'correct' :
'wrong'
})
</p>
</>
);
}์ด ํ์ด์ง์ ์ค๋ช ๋ ๋ฐ๋ก ๊ทธ ์๊ณ ๋ฆฌ์ฆ์ด React๊ฐ ์ต์ข state๋ฅผ ๊ณ์ฐํ๋ ๋ฐ ์ฌ์ฉํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค.
export function getFinalState(baseState, queue) {
let finalState = baseState;
for (let update of queue) {
if (typeof update === 'function') {
// Apply the updater function.
finalState = update(finalState);
} else {
// Replace the next state.
finalState = update;
}
}
return finalState;
}import { getFinalState } from './processQueue.js';
function increment(n) {
return n + 1;
}
increment.toString = () => 'n => n+1';
export default function App() {
return (
<>
<TestCase
baseState={0}
queue={[1, 1, 1]}
expected={1}
/>
<hr />
<TestCase
baseState={0}
queue={[
increment,
increment,
increment
]}
expected={3}
/>
<hr />
<TestCase
baseState={0}
queue={[
5,
increment,
]}
expected={6}
/>
<hr />
<TestCase
baseState={0}
queue={[
5,
increment,
42,
]}
expected={42}
/>
</>
);
}
function TestCase({
baseState,
queue,
expected
}) {
const actual = getFinalState(baseState, queue);
return (
<>
<p>Base state: <b>{baseState}</b></p>
<p>Queue: <b>[{queue.join(', ')}]</b></p>
<p>Expected result: <b>{expected}</b></p>
<p style={{
color: actual === expected ?
'green' :
'red'
}}>
Your result: <b>{actual}</b>
{' '}
({actual === expected ?
'correct' :
'wrong'
})
</p>
</>
);
}์ด์ React์ ์ด ๋ถ๋ถ์ด ์ด๋ป๊ฒ ์๋ํ๋์ง ์ ์ ์์ต๋๋ค!