๐ค ์์ํ๋ฉฐ
์ต๊ทผ ๊ณผ์ ํ ์คํธ๋ฅผ ๋ณด๋ฉด์ ๋ฌดํ์คํฌ๋กค ๊ตฌํ ์ useEffect๊ฐ ๋ด ๋ง์๋๋ก ๋์์ง ์์๋ค.
์ถํ ํด๊ฒฐํ๊ธด ํ์ง๋ง, ๋๋ useState์ useEffect์ฌ์ด์์ ๋ญ๊ฐ ์ด๋ค๊ฒ ๋จผ์ ์คํ๋๋์ง ์์ ์๊ฒ ๋งํ ์ ์์๋ค.
๊ฒฐ๊ตญ ์์์ ์ฐ๋ฆฌ๊ฐ ์ฒ์ ๋ฆฌ์กํธ๋ฅผ ๋ฐฐ์ธ๋ ํท๊ฐ๋ ธ๋ ๊ฐ์ฅ ๊ธฐ์ด์ ์ธ ์์ ์์ ์์ํ๋ค.
const handleClick = () => {
setCount(count + 1);
console.log(count); // ์ด์ ๊ฐ์ด ์ฐํ
};
์ ์ฌ๊ธฐ์ ์ด์ ๊ฐ์ด ์ฐํ๋๊ฐ ? ์ ๋ฐ๋ก count+1๋ ๊ฐ์ด ์ฐํ์ง ์๋๊ฑธ๊น? state๋ ์ธ์ ์ ๋ฐ์ดํธ ๋๋๊ฑธ๊น?
์ด์ ๋ํ ๋ต์ ์์๋ณด๋๋ก ํ๊ฒ ๋ค.
๐ ๋๊ธฐ์ ๋น๋๊ธฐ ๊ฐ๋จ ์ ๋ฆฌ
๋๊ธฐ(sync) : ์คํ์์๊ฐ ๋ณด์ฅ๋๋ ๊ฒ์ ๋ปํ๋ค. ํธ์ถ ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ก ํ์ธํ ์ ์๋ค. (const
, let
, for
, if
, function
, console.log()
๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ js์ ํจ์๋ ๋ชจ๋ ๋๊ธฐ์ด๋ค.)
๋น๋๊ธฐ(async) : ์คํ์์๊ฐ ๋ณด์ฅ๋์ง ์๋๊ฒ์ ๋ปํ๋ค. ํธ์ถ ์ ๊ฒฐ๊ณผ๊ฐ ๋์ค์ ๋์ฐฉํ๋ค. (setTimeout
, fetch
, Promise
, await
)
์ฌ๊ธฐ์ ์ ๊น ์๋ฐ์คํฌ๋ฆฝํธ์ ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ์ง๊ณ ๋์ด๊ฐ์๋ฉด ์๋์ ๊ฐ์ ํํ์ด๋ค.
์ฝ์คํ์์ ํธ์ถ๋ ํจ์๊ฐ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํ๋๊ณ ์ด์๋ํ ์ฝ๋ฐฑํจ์๋ค์ด ์ฝ๋ฐฑํ๋ก ๋์ด๊ฐ๋ค.
MicroTaskQueue์ ๋ด๊ธฐ๋ ๋น๋๊ธฐ ๋์ : Promise, await, queueMicrotask
MacroTaskQueue์ ๋ด๊ธฐ๋ ๋น๋๊ธฐ ๋์ : setTimeout, setInterval, DOM ์ด๋ฒคํธ ๋ฑ
(์ฐ์ ์์๋ MicroTaskQueue > CallbackQueue ์ด๋ค )
โ๏ธ React ์ํ ์ ๋ฐ์ดํธ ํ๋ฆ
React์ ๋ ๋๋ง ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ๋ค. (setState → render → commit → effect)
์ ์ด์ ๋ค์ ์์๋ฅผ ๋ณด์
const handleClick = () => {
setCount(count + 1);
console.log(count); // ์ด์ ๊ฐ์ด ์ฐํ
};
์ ์์์์ ์ ์ด์ ๊ฐ์ด ์ฐํ๊น?
๊ทธ๊ฑด ๋ฐ๋ก setState๊ฐ ์ฆ์ ์คํ๋๋๋ผ๋ ์ค์ ๋ฐ์์ ๋ ๋๋ง ์ดํ์ ์ผ์ด๋๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ ์ํ๋ snapshot(์ ์ ์ธ UI ๋ณต์ฌ๋ณธ)์ฒ๋ผ ๋์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
Rendering : ์ด๋ React๊ฐ ์ปดํฌ๋ํธ์ธ ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
ํด๋น ํจ์์์ ๋ฐํํ๋ JSX ์ปดํฌ๋ํธ๋ ์๊ฐ์ ๋ฐ๋ฅธ UI์ค๋
์ท๊ณผ ๊ฐ๋ค.
ํ๋กํผํฐ, ์ด๋ฒคํธํธ๋ค๋ฌ, ๋ก์ปฌ๋ณ์ ๋ชจ๋ ๋ ๋๋ง ๋น์์ ์ํ(์ค๋
์ท)๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ณ์ฐ๋๋ค.
๊ทธ๋์ ๋ฆฌ์กํธ๋ ์ด ์ค๋
์ท์ ๋ง๊ฒ ํ๋ฉด์ ์
๋ฐ์ดํธํ๊ณ , ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ฐ๊ฒฐํ๋ค.
๋ ๋๋ง ์์ → count = 0
↓
ํด๋ฆญ ๋ฐ์ → handleClick() ์คํ
↓
setCount(count + 1) → setCount(0 + 1) → "์
๋ฐ์ดํธ ์์ฝ"
↓
console.log(count) → 0 ← ์์ง ๋ฆฌ๋ ๋๋ง ์ ๋์ผ๋๊น!
↓
React๊ฐ ๋ฆฌ๋ ๋๋ง → count = 1
##
์ด๋ ๊ฒ ์ค๋ ์ท์ฒ๋ผ ์ ์ฅ๋๋ ์ด์ ๋ React์ Batching ์๊ณ ๋ฆฌ์ฆ ๋๋ฌธ์ด๋ค.
React๋ ํจ์จ์ ์ธ ์ํ ์
๋ฐ์ดํธ๋ฅผ ์ํด ์ฌ๋ฌ ๊ฐ์ setState
ํธ์ถ์ ์ฆ์ ๋ฐ์ํ์ง ์๊ณ ,
"ํ๋์ ๋ ๋๋ง ์ฌ์ดํด๋ก ๋ฌถ์ด์ ํ๊บผ๋ฒ์ ์ฒ๋ฆฌ" ๋ฐฐ์นญ(Batching) ๊ณผ์ ์ ๊ฑฐ์น๋ค.
์ด ๋๋ถ์ ๋ฆฌ์กํธ๋ ์ฑ๋ฅ์ ์ต์ ํํ๊ณ , ๋ถํ์ํ ๋ ๋๋ง์ ์ค์ผ ์ ์์ผ๋ฉฐ ๊ธฐ์กด์ ์
๋ฐ์ดํธ์ ๋นํด ๋น ๋ฅธ ์ฑ๋ฅ์ ์ ์งํ ์ ์๋ค.
์ฌ๊ธฐ์ ์ค์ํ๊ฑด
setState()
๋ ์ํ๋ฅผ "์ฆ์ ๋ณ๊ฒฝ"ํ๋ ๊ฒ์ด ์๋๋ผ React์ ์
๋ฐ์ดํธ ํ์ "๋ณ๊ฒฝ ์์ฒญ์ ๋ฑ๋ก"๋ง ํ๋ค.
React๋ ํ์ฌ ์คํ ์ค์ธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ๋ ๋๋ง์ด ๋๋ ๋ค์ ๋ชจ๋ ์ํ ์
๋ฐ์ดํธ๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ํ์ ์์๋๋ค.
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
- ์์ ์์๋ ๋ง์ฝ ๋ฐฐ์นญ์ด ์๋ค๋ฉด ๋ ๋๋ง์ด 3๋ฒ ๋ฐ์ํ ๊ฒ์ด๋ค.
- ํ์ง๋ง ๋ฐฐ์นญ ๋๋ถ์ React๋ ํ๋ฒ์ ๋ ๋๋ง๋ง ์คํํ๋ค.
- ๊ทธ๋ฆฌ๊ณ ์ด ๋ชจ๋ setCount๋ ๊ฐ์ count=0์ด๋ ์ํ์ ์ค๋ ์ท ๊ธฐ๋ฐ์ด๋ผ ๊ฒฐ๊ณผ๋ ๊ฒฐ๊ตญ count+1์ด๋ค.
- ๊ฒฐ๊ตญ ๋ค์ ๋ ๋๋ง์์์ ์ํ ๋ณํ๋, ์ด์ ๋ ๋๋ง ์์ ์ "์ค๋ ์ท"์ ๊ธฐ์ค์ผ๋ก ๋ง๋ค์ด์ง ์ ๋ฐ์ดํธ ์์ฒญ์ ์ฒ๋ฆฌํ ๊ฒฐ๊ณผ์ธ ๊ฒ์ด๋ค.
๊ทธ๋์ ๋ง์ฝ ํจ์ํ ์ ๋ฐ์ดํธ๋ฅผ ์ฐ๊ณ ์ถ๋ค๋ฉด ๋ฆฌ์กํธ๊ฐ ๊ถ์ฅํ๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์์ ์จ์ผํ๋ค.
setCount(prev => prev + 1);
setCount(prev => prev + 1);
- ์ด ๋ฐฉ์์์ React๊ฐ ์ฒซ ๋ฒ์งธ ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์๋ ์งํ์ ์ต์ ๊ฐ์ ๋ ๋ฒ์งธ์๋ ๋๊ฒจ์ค๋ค.
- ์ฆ, React๋ ์ด ๋ ๊ฐ๋ฅผ ์์๋๋ก "ํ์ ์ ์ฅ"ํ๋ค๊ฐ
๊ฐ ์ฝ๋ฐฑ์ ์ต์ ๊ฐ ๊ธฐ์ค์ผ๋ก ์ฐจ๋ก๋ก ์คํํ๋ค. prev => ...
ํํ์ ์ ๋ฐ์ดํธ๋ React๊ฐ ์ํ ๋ณ๊ฒฝ์ ์ฒ๋ฆฌํ ๋- "์ด์ ์ํ๋ฅผ ๋๊ฒจ์ค๊ฒ, ๋ค๊ฐ ๊ณ์ฐํด๋ด" ๋ฐฉ์์ด๊ธฐ ๋๋ฌธ์ ํจ์ํ ์ ๋ฐ์ดํธ๋ ํญ์ ์ต์ ๊ฐ์ ๋ฐ๋๋ค
- ์ด ๋๋ถ์ ๋ ๋๋ง ์ค ๋ง๋ค์ด์ง ์ค๋
์ท์ ์์กดํ์ง ์๊ณ ,
์ค์ ๋ก ํ ์ฒ๋ฆฌ ์์์ ๋ฐ๋ผ ์ต์ ๊ฐ์ ์์ ํ๊ฒ ๊ณ์ฐํ ์ ์๋ค.
์ผ๋ฐ ์ ๋ฐ์ดํธ:
"๋ด๊ฐ ๋ณธ ์ํ(์ด์ snapShot)(count=0)์์ 1 ๋ํด์ค!"
ํจ์ํ ์ ๋ฐ์ดํธ:
"๋ค๊ฐ ์๊ณ ์๋ ๊ฐ์ฅ ์ต์ ์ํ(์ด์ ์ +1๋ ์ํ)(prev)๋ฅผ ์๋ ค์ฃผ๋ฉด, ๊ฑฐ๊ธฐ์ 1 ๋ํ ๊ฒ."
๐ ์ค์ ํ๋ฆ ์์ฝ
const handleClick = () => {
setCount(count + 1); //์ด์ ์ค๋
์ท(count : 0) +1
console.log(count); //์ด์ ์ค๋
์ท(count : 0)
};
๊ฒฐ๊ณผ :
0
โ ๊ฒฐ๋ก : ๋๊ธฐ์ธ๊ฐ, ๋น๋๊ธฐ์ธ๊ฐ?
state ๋ ๋๊ธฐ์ด๋ค. useEffect๋ ๋๊ธฐ์ด๋ค.
ํ์ง๋ง ๋ฆฌ์กํธ ๋ด๋ถ์ ์ค์ผ์ฅด๋ง (๋ฆฌ์กํธ ๋ด๋ถ์์ js๋ฐํ์๊ณผ ๋ฌ๋ฆฌ ์ค์ผ์ฅด๋ง ๋๋ค.)์ ์ํด useState์ useEffect์ ์คํ์์ ์ด ๋ค๋ฅด๋ค
useState: ์ฌ๋ ๋๋ง ํ๋ผ๋ Trigger
useEffect: state์ ์ํ sideEffect๋ฅผ ์ฒ๋ฆฌํ๋ ์ฉ๋ ์ด๊ธฐ ๋๋ฌธ์ useEffect์ ๋์์ ๋ ๋๋ง ์ดํ mount ๋ํ (DOM์ ๋ฐ์ดํธ) ์ดํ์ ์คํ๋๋ค
์ํ ๋ณ๊ฒฝ ๋ฐ์(setState ํธ์ถ ๋ฑ)
โฌ๏ธ ์ํ ๋ณ๊ฒฝ ๋ฐฐ์นญ
โฌ๏ธ ๋ ๋๋ง (return ๋ฌธ ์คํ)
โฌ๏ธ ํ๋ฉด(DOM) ์
๋ฐ์ดํธ
โฌ๏ธ useEffect ์คํ
(์ด๊ฒ๋ ์ค๊ฐ์ ๋น๋๊ธฐ ํจ์๊ฐ ๊ปด์๋๋ ์๋๋์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ฐ, ์ด๋ ๋ค์์ ์ธ ๊ธ์์ ์๋๋ก ํ๊ฒ ๋ค.)
๐ ํ๋ก ์ ๋ฆฌํ๋ฉด
โ React ์ํ ์ ๋ฐ์ดํธ ๋ฐ ์คํ ํ๋ฆ ์์ฝ ํ
๋จ๊ณ | ์์ / ์คํ ๋์ | ์ค๋ช |
---|---|---|
1๏ธโฃ | setState() ํธ์ถ |
์ํ ๋ณ๊ฒฝ ์์ฒญ (์ฆ์ ์คํ๋จ) |
2๏ธโฃ | ์ ๋ฐ์ดํธ ์์ฝ | ์ํ๋ ์์ง ๋ณ๊ฒฝ๋์ง ์์. React์ ์ ๋ฐ์ดํธ ํ์ ์ ์ฅ๋จ |
3๏ธโฃ | ๋ฐฐ์นญ ์ฒ๋ฆฌ | ์ฌ๋ฌ setState() ๊ฐ ๋ชจ์ด๋ฉด ํ ๋ฒ์ ์ฒ๋ฆฌ๋จ (๋ฐฐ์นญ) |
4๏ธโฃ | ์ปดํฌ๋ํธ ์ฌ๋ ๋๋ง | ์๋ก์ด ์ค๋ ์ท ์์ฑ. ์ด ์์ ์ state, props, ๋ณ์๋ค์ "๊ณ ์ "๋จ |
5๏ธโฃ | DOM ์ ๋ฐ์ดํธ (Commit Phase) | ์ค์ DOM์ ๋ณ๊ฒฝ์ฌํญ ๋ฐ์๋จ |
6๏ธโฃ | useEffect() ์คํ |
๋ ๋๋ง ์ดํ ์คํ๋๋ ์ฌ์ด๋ ์ดํํธ ์ฒ๋ฆฌ ์์ญ |
๐ ์ผ๋ฐ ์ ๋ฐ์ดํธ vs ํจ์ํ ์ ๋ฐ์ดํธ ๋น๊ต ํ
๋ฐฉ์ | ์ฝ๋ ์์ | ์ฒ๋ฆฌ ๊ธฐ์ค | ๊ฒฐ๊ณผ |
---|---|---|---|
์ผ๋ฐ ์ ๋ฐ์ดํธ | setCount(count + 1) |
๋ ๋๋ง ๋น์์ ์ค๋ ์ท ๊ธฐ์ค | ์ฌ๋ฌ ๋ฒ ํธ์ถํด๋ ๊ฐ์ ๊ฐ ๊ธฐ์ค → ๋์ ๋์ง ์์ |
ํจ์ํ ์ ๋ฐ์ดํธ | setCount(prev => prev + 1) |
React๊ฐ ์ต์ ์ํ๋ฅผ ๋๊ฒจ์ค | ์ต์ ์ํ ๊ธฐ์ค → ๋์ ๊ฐ๋ฅ |
๐ ์ํ์ useEffect ์คํ ํ๋ฆ ๋น๊ต
ํญ๋ชฉ | ์คํ ์์ | ๋น๊ณ |
---|---|---|
setState() |
๋๊ธฐ (์ฆ์ ์คํ) | ์ค์ ์ํ ๋ฐ์์ ๋์ค์(Batcing์ผ๋ก ํ๋ฒ์ ์ฒ๋ฆฌ) |
๋ ๋๋ง (return ) |
์ํ ๋ณ๊ฒฝ ์งํ | JSX → Virtual DOM ๊ณ์ฐ |
useEffect() |
๋ ๋๋ง & DOM ์ ๋ฐ์ดํธ ์ดํ | ๋น๋๊ธฐ์ฒ๋ผ ์๋. ์ฌ์ด๋ ์ดํํธ ์ฒ๋ฆฌ์ฉ |
๐ ํต์ฌ ๊ฐ๋ ์ ๋ฆฌํ
๊ฐ๋ | ์ค๋ช |
---|---|
์ค๋ ์ท | ๋ ๋๋ง ์์ ์ ์ํ, props, ํด๋ก์ ๋ค์ด ๊ณ ์ ๋ ์ํ |
๋ฐฐ์นญ(Batching) | ์ฌ๋ฌ ์ํ ๋ณ๊ฒฝ์ ํ๋์ ๋ ๋๋ง์ผ๋ก ์ฒ๋ฆฌํ์ฌ ์ฑ๋ฅ ์ต์ ํ |
ํจ์ํ ์ ๋ฐ์ดํธ | ์ต์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ํ๋ฅผ ๊ณ์ฐํ ์ ์๊ฒ ํ๋ React ๊ธฐ๋ฅ |
useEffect ์คํ ์์ | ๋ ๋๋ง ํ, ์ค์ DOM ์ปค๋ฐ ์ดํ |
๊ฒฐ๋ก
React์ ์ํ๋ ๋๊ธฐ์ ์ผ๋ก ์คํ๋์ง๋ง, ๊ฒฐ๊ณผ๋ ๋น๋๊ธฐ์ฒ๋ผ ๋ฐ์๋๋ฉฐ, ์ด ๋ชจ๋ ๊ตฌ์กฐ๋ ๋ฐฐ์นญ๊ณผ ๋ ๋๋ง ์ค์ผ์ค๋ง ๋๋ถ์ด๋ค.
โจ ๋ง๋ฌด๋ฆฌ ํฌ์ธํธ ์์ฝ
function App() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
setCount(count + 1);
console.log("clicked!", count); // โ
์ฌ๊ธฐ์๋ ์ฌ์ ํ ์ด์ count ๊ฐ
};
useEffect(() => {
console.log("effect!", count); // โ
์ฌ๊ธฐ๋ ์
๋ฐ์ดํธ๋ ๊ฐ
}, [count]);
return <button onClick={handleClick}>Click</button>;
}
- ์์ฒ๋ผ ์ ๋ฐ์ดํธ ๋๋ ์๊ฐ์ ์ด๋ฒคํธํธ๋ค๋ฌ๊ฐ ๋ค ์คํ๋์์ ๋์ด๋ค.
- ๊ทธ๋์ ์ธ์ ์ ๋ฐ์ดํธ๊ฐ ๋๋๊ฑธ๊น ?
ํธ๋ฆฌ๊ฑฐ | ์ํ ์ ๋ฐ์ดํธ๊ฐ ์ค์ ๋ก ๋ฐ์๋๋? | ๋น๊ณ |
---|---|---|
React ์ด๋ฒคํธ ํธ๋ค๋ฌ | โ Yes | ๋ ๋๋ง ํธ๋ฆฌ๊ฑฐ๋จ (๋ฐฐ์นญ ์ ์ฉ) |
useEffect ๋ด๋ถ | โ Yes | ์ฌ์ด๋ ์ดํํธ ํ ์ํ ๋ฐ์ ๊ฐ๋ฅ |
Promise.then / setTimeout | โ Yes (React 18+) | ์๋ ๋ฐฐ์นญ ํ์ฅ๋จ |
๋จ์ setState ํธ์ถ ํ console.log | โ No | ์์ง ๋ ๋๋ง ์ ๋จ |
๐ ๋ค์์ ๋ค๋ฃฐ ๋ด์ฉ
- useEffect์์ fetch์ ๊ฐ์ ๋น๋๊ธฐ ํจ์๊ฐ ์์๋๋ ๋๊ธฐ ๋ด์ฉ๋ง ์์๋๋ ๋ ์ด๋ฒคํธ ๋ฃจํ์ ๋์์ด ๋ค๋ฅด๋๋ผ๊ตฌ์
- ๊ทธ๋์ ๋ค์ ๊ธ์ useEffect์์ ์ด๋ป๊ฒ ํ๋ฆ์ด ์ด์ด์ง๋์ง ์์๋ณผ ์์ ์ ๋๋ค.
Reference
React
React is the library for web and native user interfaces. Build user interfaces out of individual pieces called components written in JavaScript. React is designed to let you seamlessly combine components written by independent people, teams, and organizati
react.dev
https://sckimynwa.medium.com/react-mount-system-deep-dive-sync-mode-c89c1ace14af
React Mount System Deep Dive (Sync Mode)
Overview
sckimynwa.medium.com