๐ก 10. ์ง์ ํ ์ต์ ํ: ์ํคํ ์ฒ์ Children ํจํด
๐ ๊ฐ์
useMemo ๋จ๋ฐ ๋์ , ๋ฆฌ์กํธ์ ๋ณธ์ง์ธ Children(ํฉ์ฑ)๊ณผ ์ํ ๊ฒฉ๋ฆฌ(Colocation)๋ฅผ ์ด์ฉํด ๋ ๋๋ง ํญํฌ์๋ฅผ ๊ทผ๋ณธ์ ์ผ๋ก ๋์ด๋ด๋ ํ๋ก ํธ์๋ ์ต์ ํ์ ๊ทน์๋ฅผ ๋ฐฐ์๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ์ต์๋จ ์ปดํฌ๋ํธ์ ์ํ๊ฐ ์์ ๋ ๋ฐ์ํ๋ ๋ฌด์๋ฏธํ ๋ ๋๋ง์ ๊ตฌ์กฐ์ ์ผ๋ก ์ฐข์ด์ ํด๊ฒฐํ ์ ์๋ค.
React.memo๋ฐ์ ์์ด๋,childrenprop ํฉ์ฑ(Composition)๋ง์ผ๋ก ๋ง๋ฒ์ฒ๋ผ ๋ ๋๋ง์ ๋ง์๋ด๋ ๋ฉ์ปค๋์ฆ์ ํฐ๋ํ๋ค.- ์ํ ๊ด๋ฆฌ ๋๊ตฌ๋ ํ (Hooks)์ ๊ธฐ๋๊ธฐ ์ ์, "๋ฐ์ค(Component)๋ฅผ ์ด๋ป๊ฒ ์ชผ๊ฐค ๊ฒ์ธ๊ฐ" ๋ถํฐ ๊ณ ๋ฏผํ๋ ์ง์ง ์๋์ด๋ก ์งํํ๋ค.
๐ ๋ชฉ์ฐจ
- ๐ค ์ ์์์ผ ํ๋๊ฐ: ๊ฐ๋ผํ๊ณ ์ค์์ ๋ฒ์ด๋๊ธฐ
- ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ ๊ทน์ ์ฒด๋: ์ง์ ํ ์ต์ ํ 2๋ ๋ฐฉ์ด๋ง
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 15๋ถ / ํต์ฌ ํํธ: 10๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ์์ฒ (์ ์
): "์ ๋ฐฐ๋, ํ๋ฉด ๊ตฌ์์ ์๋ ์์ํ(Color Picker) ํ๋ ์์ง์๋๋ฐ ์ ์ค์์ ์๋ ์๋ฐฑ ๊ฐ์ ํ(Table) ์
๋ค์ด ์น ๋ค ๋ฆฌ๋ ๋๋ง๋๋์?
React.memo๋ก ํ ์ 1000๊ฐ๋ฅผ ๋ค ๊ฐ์ธ๋ฒ๋ฆฌ๋ฉด ๋ ๊น์?" - ์ํธ(๋ฆฌ๋): "์์ฒ ๋. ์ฝ๋๋ฅผ ๋์ง๋์ง ๊ธฐ์ ๋ถ์ด๋ ค๋ ์๊ฐ์ ๋ฒ๋ฆฌ์ธ์. ์ด๊ฑด ์ฝ๋ฉ(Hooks)์ ๋ฌธ์ ๊ฐ ์๋๋ผ ๊ฑด์ถ๋ฌผ ๋ผ๋(Architecture)์ ๋ฌธ์ ์ ๋๋ค. ํ๋ฅผ ๊ฐ์ธ๋ ๋ฒฝ์ ํ๋ฌผ๊ณ ์ฌ๋ฐฐ์นํด๋ณด์์ฃ ."
๐ค ์ ์์์ผ ํ๋๊ฐ: ๊ฐ๋ผํ๊ณ ์ค์์ ๋ฒ์ด๋๊ธฐ
๊ฐ์ฅ ์ํ๊น์ด ์ํฉ์, ์ด๋ณด์๋ค์ด ์ํ๋ฅผ ๋์ด์ฌ๋ ค ๋๊ณ ๋ ๋ ๋ (Jank)์ด ๋ฐ์ํ๋ฉด ๊ณง์ฅ useMemo, useCallback, React.memo๋ฅผ ์์ญ ๊ฐ ๋ณต๋ถํ๊ธฐ ์์ํ๋ค๋ ๊ฒ๋๋ค.
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
์์ฒ ์ด๊ฐ ์ง ์ด ๋ฌด๊ฑฐ์ด ๋์๋ณด๋. ์๋จ์ ์์ฃผ ๊ฐ๋ฒผ์ด ์์(ํ ๋ง)๋ง ์ค์๊ฐ์ผ๋ก ๋ฐ๊พธ๊ณ ์ถ์๋ฐ... ์ ์ ์๋ ๋ฌด๊ฑฐ์ด ์ฐจํธ๊น์ง ๋ค ์ฌ๊ณ์ฐ๋๋ ๋์ฐธ์ฌ๊ฐ ํฐ์ง๊น?
// โ ์์ฒ ์ด์ ํญํ ์ํคํ
์ฒ (State in root)
function BigDashboard() {
// ์ฌ์ฉ์๊ฐ ์ปฌ๋ฌ ์ฌ๋ผ์ด๋๋ฅผ ์ซ- ๋๋๊ทธํ๋ฉด ์ด ์ํ๊ฐ ์ด๋น 60ํ๋ ์์ผ๋ก ๋ฐ๋๋ค!
const [color, setColor] = useState("red");
return (
<div style={{ background: color }}>
<input type="color" onChange={(e) => setColor(e.target.value)} />
{/* ๐ฅ ์ด ๋
์๋ค์ ์์๊ณผ 1๋ ๊ด๋ จ์ด ์์ง๋ง ๋ถ๋ชจ๊ฐ ๋ ๋๋ง๋๋๊น ๊ฐ์ ๋ก ๊ฐ๋ ค ๋๊ฐ๋ค */}
<VeryHeavyChartA />
<VeryHeavyChartB />
<MonsterGridTable />
</div>
);
}์ด๊ฑธ ๊ณ ์น๋ผ๊ณ ํ๋ฉด 99%์ ์ฃผ๋์ด๋ค์ ํ์ ์ปดํฌ๋ํธ 3๊ฐ๋ฅผ ์ ๋ถ React.memo ๋ก ๊ฐ์ธ๋ ค๊ณ ๋ญ๋๋ค. ์ํธ(5๋
์ฐจ ์๋์ด)๋ ๊ทธ๋ ๊ฒ ํ์ง ์์ต๋๋ค. ์ํธ์ ๋ฌด๊ธฐ๋ ์ค์ง "๊ตฌ์กฐ(Component Split)" ์
๋๋ค.
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
๋ฐฉ๋ฒ 1 (๋ ๋ ์ต์ ํ ํ ๋ฉ์ด๋ฆฌ - ์์ฒ ):
๊ต์ฅ ์ ์๋(๋ถ๋ชจ ์ปดํฌ๋ํธ)์ด ๋ง์ดํฌ๋ก ์์๋ฆฌ(์ํ ๋ณ๊ฒฝ)๋ฅผ ์์ํ์ด!
๊ทธ ์๋ฆฌ๋ฅผ ๋ค ๋ค์ด์ผ ํด์ ๊ฐ๋น์ 1ํ๋ ๋ถํฐ 6ํ๋ ํ์ ์ ์ฒด๊ฐ ๊ท๋ฅผ ๋ง๊ณ ๊ดด๋กญ๊ฒ ๋ชธ์ ๋นํ์ง(๋ฆฌ๋ ๋๋ง).
์์ฒ ์ด๋ ์ด๊ฑธ ๋ง์๋ณด๊ฒ ๋ค๊ณ ํ์ 1000๋ช ์๊ฒ ์ผ์ผ์ด ๋ฐฉ์ ํค๋ํฐ(React.memo) ์ ์ฌ์ ๊ฐ์ ๋ก ์์ฐ๊ณ ์์ด. ๋๊ณผ ๋ ธ๋ ฅ์ด ์์ฒญ ๊นจ์ง๊ฒ ์ง?๋ฐฉ๋ฒ 2 (์ํคํ ์ฒ ๊ตฌ์กฐ์ ๋ง๋ฒ - ์ํธ):
์ํธ๋ ํ์๋ค์๊ฒ ํค๋ํฐ์ ์์ธ ์๊ฐ์กฐ์ฐจ ์ ํด. ๋์ ๊ต์ฅ ์ ์๋์ ์๊ณ ์ข์ ๋ฐฉ(๊ณ ๋ฆฝ๋ ์์ ์ปดํฌ๋ํธ) ์์ผ๋ก ์ง์ด๋ฃ์ ๋ค์ ๋ฌธ์ ์พ ๋ซ์๋ฒ๋ ค!(์ํ ๊ฒฉ๋ฆฌ / Colocation)
๊ต์ฅ ์ ์๋์ด ๋ฐฉ ์์์ ํผ์ ์ถค์ถ๊ณ ๊ฝน๊ณผ๋ฆฌ๋ฅผ ์ณ๋(์ํ ๋ณ๊ฒฝ), ๊ฐ๋น์ ์๋ ํ์ ์ปดํฌ๋ํธ๋ค์ ๋ฌด์จ ์ผ์ด ์ผ์ด๋๋์ง๋ ๋ชจ๋ฅธ ์ฑ ํ์จํ๊ฒ ๋์. (๋ฌด๊ฒฐ์ ๋ ๋๋ง ๋ฐฉ์ด ์ฑ๊ณต)
์ด๊ฒ ๋ฐ๋ก "์ํ ๋ฐ์ด ๋ด๋ฆฌ๊ธฐ(State Push-down)" ์ "์ปดํฌ๋ํธ ํฉ์ฑ(Composition)" ์ ์๋ ฅ์ ๋๋ค.
๐งฉ ๊ทน์ ์ฒด๋: ์ง์ ํ ์ต์ ํ 2๋ ๋ฐฉ์ด๋ง
โ ๋ฐฉ์ด์ 1. ์ํ๊ฐ ๋ณํ๋ ๋ฒ์ธ์ ์งํ ๊ฐ์ฅ์ ๊ฐ๋๊ธฐ (State Push-Down)
๋ฌด๊ฑฐ์ด ์ฐจํธ(Heavy)๋ค์ ์ ์ด์ ์ color ์ํ ๋ณ์์ ์ฎ์ผ ์ด์ ๊ฐ ๋จ 1%๋ ์๋ ๋จ๋จ์
๋๋ค.
์ด๋ด ๋, ์ํ๋ฅผ ์ฌ์ฉ(์๋น)ํ๋ ๋
์๋ค๋ง ๋ฑ ํ์
์ผ๋ก ์ง์ด์ ๋ณ๋์ ์ปดํฌ๋ํธ๋ก ๋นผ๋ธ ๋ค์ ๊ทธ ์์ผ๋ก ์ํ๋ฅผ ๋์ ธ๋ฒ๋ฆฝ๋๋ค(๊ณ ๋ฆฝ).
// โ
๋ฆฌํฉํ ๋ง 1. color ์ํ๋ฅผ ๊ฒฉ๋ฆฌ์ํจ ๋ฐฉ์ด๋ง ์ปดํฌ๋ํธ ์ ์
function ColorPickerWrapper() {
const [color, setColor] = useState("red");
// ๐ฏ ์ด ์ปดํฌ๋ํธ๋ ์ค์ง ์์ ๋ง ๋ถ์๊ณ ๋ฆฌ๋ ๋๋ง๋๋ค. ์์ง ๋์๋ณด๋์ ํผํด๋ฅผ ์ ์ค!
return (
<div style={{ background: color }}>
<input type="color" onChange={(e) => setColor(e.target.value)} />
</div>
);
}
// ๋ถ๋ชจ: ํ-์จ. ํ ๋ฒ ๋ ๋๋ง๋๊ณ ๋๋ฉด ์์ํ ๋ค์ ๋ถ๋ฆฌ์ง ์๋๋ค.
function BigDashboard() {
return (
<>
<ColorPickerWrapper />
{/* ์ด์ ๋ถํฐ ์๋ค๋ค์ ๊ต์ฅ์ ์๋ ๋ฐฉ๊ณผ ๋ถ๋ฆฌ๋์ด ์์ ํ ์์ ํจ */}
<VeryHeavyChartA />
<VeryHeavyChartB />
</>
);
}๊ฒฐ๊ณผ: ๋จ 1๊ฐ์ useMemo, React.memo ์์ด ๋ฌด๊ฑฐ์ด ์ปดํฌ๋ํธ๋ค์ ํญํฌ์ ๋ ๋๋ง์ 100% ๋์ด๋์ต๋๋ค.
โ ๋ฐฉ์ด์ 2. ์์(Children)์๊ฒ ์ง ๋ ์๊ธฐ (Composition)
์์ ์์๋ ๊น๋ํ๊ฒ ์์ผ๋ก ์น์ ์ผ๋๊น ์ฌ์ ์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ง์ฝ ์ ์๊น ๊ป๋ฐ๊ธฐ <div style={{background: color}}> ์์ ๋ฐ๋์ ์ ํค๋นํ ์ฐจํธ๋ค์ ์์ ์์๋ก ์ง์ ํ๊ณ ํ์ด์ ธ์ผ ๋งํฌ์
(UI ๋ ์ด์์) ๊ตฌ์กฐ ๋ผ๋ฉด ์ด๋จ๊น์? ๋ชป ๋๋ง๊ฐ๋๋ค!
// "๋๋ง์น ์ ์๋ค. ๋ด ํ ์์ ๋ฌด๊ฑฐ์ด ์ ๋ค์ ๊ทธ๋ ค์ผ๋ง ํ๋ค."
function ThemeApp() {
const [color, setColor] = useState("red");
return (
<div style={{ background: color }} className="layout-box">
<input type="color" onChange={(e) => setColor(e.target.value)} />
{/* ๐ฅ ๋ ์ด์์์ ์ด ๋ฐ์ค ์์ ๋ค์ด๊ฐ์ผ ํ๋ ๊ฐ์ด ๋ ๋๋ง ์ง์ฅ์ ๋น ์ง! */}
<VeryHeavyChartA />
</div>
);
}์ด๋ด ๋ ์ฐ๋ ํ๋ก ํธ์๋ ์ตํ์ ๋ง๋ฒ ์ฃผ๋ฌธ์ด ๋ฐ๋ก ๊ตฌ๋ฉ ๋ซ๊ธฐ, {children} ๊ตฌ๋ฉ ๋ด๊ธฐ ์
๋๋ค.
์์ ๋ฒ์ธ ๊ป๋ฐ๊ธฐ(ThemeApp)๋ฅผ, ์์ด ํ
๋น **์ฌํท(๊ป๋ฐ๊ธฐ ์ปดํฌ๋ํธ)**์ผ๋ก ๋ง๋ค์ด์ ๋ถ๋ฆฌํฉ๋๋ค.
// โ
๋ฆฌํฉํ ๋ง 2-1. ์ฌํท ์ปดํฌ๋ํธ (์ํ๋ ์ฌ๊ธฐ ๊ฐํ)
function ColorBoxJacket({ children }) {
const [color, setColor] = useState("red");
return (
<div style={{ background: color }} className="layout-box">
<input type="color" onChange={(e) => setColor(e.target.value)} />
{/* ๐ฏ ๋ฆฌ์กํธ ๋ง๋ฒ: ์ด ์์์ ๋ถ๋ชจ(ColorBoxJacket)๊ฐ ๋ฆฌ๋ ๋๋ง๋์ด๋,
ํฌ์ฅ์ง(App)์์ ๋ฏธ๋ฆฌ ๋น์ด์ค '๋์ผํ ๋์'์ด๋ฏ๋ก ๋ฐฉํจ๋ฅผ ์ป๋๋ค! */}
{children}
</div>
);
}
// โ
๋ฆฌํฉํ ๋ง 2-2. ์ต์ข
์กฐ๋ฆฝ ์ค๋ช
์ ํ๋ฉด (์ํ๋ฅผ ๋ชจ๋ฅด๋ ์ฒญ์ ๊ตฌ์ญ)
function App() {
return (
<ColorBoxJacket>
{/* ๐ฏ ์ด ๋ฌด๊ฑฐ์ด ์ฐจํธ๋ App์ด ๊ทธ๋ฆฐ๋ค! App์ Color ์ํ๋ฅผ ๋ชจ๋ฅด๋
๋ฆฌ๋ ๋๋ง๋์ง ์๊ณ , ๋ฐ๋ผ์ ์ด ๋
์๋ ์์ํ ํ ๋ฒ๋ง ๊ทธ๋ ค์ ธ ์ ๋ฌ๋๋ค! */}
<VeryHeavyChartA />
</ColorBoxJacket>
);
}์ด ๊ตฌ์กฐ๋ ๋ง๋ฒ๊ณผ๋ ๊ฐ์ต๋๋ค. ์ฌ๋ผ์ด๋๋ฅผ ์ญ ๋๋ฉด ColorBoxJacket ์ปดํฌ๋ํธ๋ ์ด๋น 60๋ฒ์ฉ ๋น๋ช
์ ์ง๋ฅด๋ฉฐ ๋ฆฌ๋ ๋๋ง(๋ฐฐ๊ฒฝ์ ๊ต์ฒด)๋์ง๋ง, ๊ทธ ์
๊ตฌ(children)๋ฅผ ํตํด ์ ๊ฝํ ๋๊ธฐํ๊ณ ์๋ <VeryHeavyChartA /> ๋ ํธ๋ ํ๋ ๋ ๋๋ง๋์ง ์๊ณ ๊ตณ๊ฑดํ ์ ์ฝ ์ํ๋ฅผ ์ ์งํฉ๋๋ค. ์ด๊ฒ์ด React.memo ์์ด ๊ตฌ์กฐ์ ํฉ์ฑ(Composition)๋ง์ผ๋ก ์ด๋ฃจ์ด๋ด๋ ์ต์์, ๋๊ธฐ์
๊ธ ์๋์ด ์ต์ ํ์
๋๋ค.
๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
| ์ต์ ํ ์ํฉ | โ ์ด๋ณด์ ๋ฌด๊ธฐ (ํ์ฒ๋ฆฌ) | โ ์๋์ด์ ๋ฌด๊ธฐ (์ค๊ณ, ์ํคํ ์ฒ) |
|---|---|---|
| ์ํ ํ๋๊ฐ ์ผ๋ถ ํ์ ๋ค์ ํญ์ฌ์ํฌ ๋ | ๋ฉ์ฉกํ ํ์ ๋ค์ ์ต์ง๋ก React.memo์ ์ง์ด๋ฃ์ | ์ํ ๋ณํ์ ๋ฒ์ธ ๋ถ๋ถ๋ง ๋ถ๋ฆฌ ์ปดํฌ๋ํธ๋ก ๋ผ์ด์ ๊ณ ๋ฆฝ์ํด |
| ๊ป๋ฐ๊ธฐ ์ํ ๋ณํ๊ฐ ๋ด๋ถ ์๋งน์ด๋ฅผ ์ฃฝ์ผ ๋ | ์๋งน์ด์ ๋ฐ์
ํ๋ฉฐ useMemo/memo ๋ก์น ์๋ | ๋ฒ์ธ ๊ป๋ฐ๊ธฐ๋ฅผ children prop ๊ตฌ์กฐ๋ก ๊ตฌ๋ฉ ๋ด๊ณ ๋ฐ์์ ์๋งน์ด๋ฅผ ๊ฝ์ |
๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
"Hooks๋ ๋ง๋ณํต์น์ฝ์ด ์๋๋ค." ๋ ๋๋ง ๋ณ๋ชฉ์ด ์๊ฒผ์ ๋, ์ฒซ ๋ฒ์งธ๋ก ์์ฌํ ๊ฒ์ ์ฝ๋ฉ ๊ธฐ์ ์ด ์๋๋ผ ๋น์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์กฐ๋ฆฝํ ๋ผ๋(Tree)์ ๊ตฌ์กฐ ์ ๋๋ค. ์ปดํฌ๋ํธ์ ์ฑ ์์ ์ชผ๊ฐ๋ผ(Split). ์๋งน์ด๊ฐ ๊ผฌ์๋ค๋ฉด ํฉ์ฑ(Composition)ํด๋ผ.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ฌํ ๋ React.memo๋ก ์ปดํฌ๋ํธ๋ฅผ ์ต์ง๋ก ํ์ด๋ง๋ ๊ฒ ์ต๊ณ ์ ๊ธฐ์ ์ธ ์ค ์์๋ค. ์ํธ ์ ๋ฐฐ๊ฐ children ๊ตฌ๋ฉ ํ๋๋ก ๋ฌด๊ฑฐ์ด ์ฐจํธ ๋ ๋๋ง์ ์์ ํ ๋์ด๋์ ๋ ์ง์ง ์๋ฆ์ด ๋์๋ค.
๐ก "์ํ๊ฐ ์๋์น๋ ๋ฒ์ธ์ ์งํ ๊ฐ์ฅ์ ๊ฐ๋๊ฑฐ๋,
children์ผ๋ก ํฉ์ฑ์ ํด๋ฒ๋ฆฌ๋ฉด ์ต์ง ํ (Hook) ๋ก์น ์์ด ๊ฐ์ฅ ์์ํ๊ฒ ์ฑ๋ฅ์ ๋์ด์ฌ๋ฆด ์ ์๋ค."
Hook์ ํ๋ํจ๋ณด๋ค ์ปดํฌ๋ํธ์ ์ง ๋ผ๋, ์ํคํ ์ฒ ์์ฒด๊ฐ ํจ์ฌ ์ฐ์ํ ํด๊ฒฐ์ฑ ์ด๋ ๊ฑธ ๊นจ๋ฌ์๋ค. ์ค๋ ๋ฐฐ์ด '์ํ ๋ฐ์ด ๋ด๋ฆฌ๊ธฐ'๋ 'Children ํต๊ณผ์ํค๊ธฐ' ๋ฐฉ์ด์ ๋ง ์จ๋จน์ด๋ ์ด์ ์ด๋ ๊ฐ์ ๋ ๋ ํญ์ฃฝ ํฐ๋จ๋ ธ๋ค๊ณ ์๋จน์ ์ผ์ ์๊ฒ ์ง. ํด๊ทผ ํ ์นํจ ์์ผ๋จน์ผ๋ฉฐ ๋ฆฌ์กํธ ๋ฌธ์ ํฉ์ฑ(Composition) ํํธ๋ ํ ๋ฒ ๋ ์ ๋ ํด์ผ๊ฒ ๋ค.
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ๋ค์ ์ค ๊ณผ๋ํ ๋ ๋๋ง์ ๋ง๊ธฐ ์ํด 5๋ ์ฐจ ํ๋ก ํธ์๋ ๋ฆฌ๋๊ฐ ๊ฐ์ฅ ์ฐ์ ์ ์ผ๋ก ๊ณ ๋ ค(First Choice)ํด์ผ ํ ํด๊ฒฐ ๋ฐฉ์์ ๋ฌด์์ธ๊ฐ์?
- A) ์ปดํฌ๋ํธ ํ๋จ์ ๋ชจ๋ ์ง์ญ ํจ์๋ค์ ๋ชจ์กฐ๋ฆฌ
useCallback์ฝ๋ฐฑ์ผ๋ก ๊ฐ์ธ ๋๋ค. - B) ๋ถํ์ํ๊ฒ ๋์ ๊ณณ(์ต์๋จ)์ ์ ์ธ๋ ์ํ(State)๊ฐ ์๋ค๋ฉด, ๊ทธ ์ํ๋ฅผ ์ฌ์ฉํ๋ ๊ฐ์ฅ ๊น์ ๋ง๋จ ๊ณ์ธต(Leaf Tree)์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํด ๋ฐ์ด ๋ด๋ฆฐ๋ค(State Colocation).
- C) ๋ฌด๊ฑฐ์ด ์ปดํฌ๋ํธ ํ์ผ ์๋จ์ ์ผ๋จ ๋ฌด์ง์ฑ์ผ๋ก
export default React.memo(MyComponent)๋ฅผ ๋ฐ์๋๊ณ ์์ํ๋ค. - D)
useEffect์์ ๋ฌด๊ฑฐ์ด DOM ์ ๋ฐ์ดํธ ๋ก์ง์ ๋ชฝ๋ ์ง์ด๋ฃ๊ณsetTimeout์ผ๋ก ์ฒ๋ฆฌํ๋ค.
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค: ์ฑ๋ฅ ์ต์ ํ์ ์ 1์์น์ "ํ (Hooks)์ ๊ธฐ๋๊ธฐ ์ ์ ์ปดํฌ๋ํธ ๋ชจ๋ธ(์ค๊ณ)์ ๊ณ ์ณ๋ผ" ์ ๋๋ค. A์ C๋ ๋ถ๊ฐ์ ์ธ ์ค๋ฒํค๋(์บ์ ๊ธฐ๋ก, props ์ผ์น๋ ํ๋ณ๋ฃจํ ์ฐ์ฐ)๋ฅผ ์ ๋ฐํ๋ ๊ทน์ฝ์ฒ๋ฐฉ์ผ ๋ฟ์ ๋๋ค. ์ํ๋ฅผ ๊ณ ๋ฆฝ์ํค๋ ๋ฐฉ๋ฒ(Push State Down)์ ๋ฆฌ์กํธ ์์ง ์ ์ฅ์์ ์ถ๊ฐ์ ์ธ ํ๋ณ์ฐ์ฐ์ 0ํ๋ก ๋ง๋ค๋ฉฐ ๋ ๋๋ง ํญํฌ์๋ง ๊ตฌ์กฐ๋ฌผ๋ก ๋ฐฉ์ดํด๋ฒ๋ฆฌ๋, ๊ฐ์ฅ ์๋ฒฝํ๊ณ ๊ณต์ง์ธ ์ต์ ํ ๋น๋ฒ์ ๋๋ค.
Q2. ์ฒ ์๊ฐ React.memo ์์ด children prop(ํฉ์ฑ ๊ธฐ์ )์ ์ด์ฉํด ๋ ๋๋ง ๋ฐฉ์ด๋ฅผ ์ง๋ณด์์ต๋๋ค. ์ ์ ๊ฐ ์คํฌ๋กค์ ๋ด๋ ค ํค๋ ํฌ๋ช
๋(opacity State) ๊ฐฑ์ ์ด ์ผ์ด๋ ๋, ์ <HeavyContent />๋ ์ฌ๋ ๋๋ง ๋ฐ๋ฏธ์ง๋ฅผ 1๋ ์ ๋ฐ๊ณ ์ด์๋จ์ ์ ์์์๊น์?
function ScrollAlphaHeader({ children }) {
const [opacity, setOpacity] = useState(1);
// .. (์คํฌ๋กค ์ setState ์ฐ๋ฐ ๋ฐ๋)
return <div style={{opacity}}>{children}</div>;
}
function Page() {
return (
<ScrollAlphaHeader>
<HeavyContent />
</ScrollAlphaHeader>
);
}- A)
HeavyContent๋ด๋ถ์memo์ ์ธ์ด ๋น๋ฐ๋ฆฌ์ ๋ฆฌ์กํธ์ ๊ธฐ๋ณธ ํ์ฌ๋์ด ์์ด์. - B) ์๋น (
Page) ์ปดํฌ๋ํธ๋ ์ ํ ์ํ ๋ณํ๊ฐ ์์ผ๋ ์ฌ๋ ๋๋ง์ด ์ ๋๊ณ , ์ด๋ฏธ ๋ ๋ ๋ฌถ์์ผ๋ก ์ธ์ค<HeavyContent/>์ ์ฐธ์กฐ ์ฃผ์๊ฐ ๊ป๋ฐ๊ธฐ ์์ฒด๊ฐScrollAlphaHeader์ ๋ฆฌ๋ ๋๋ง ํ์ดํ๋ผ์ธ ์ค์๋ ์ฌ์ ํ ๋๊ฐ์ด ์ ์ง๋๊ธฐ ๋๋ฌธ. - C) CSS์
style={{opacity}}๊ตฌ๋ฌธ์ ๋ฆฌ์กํธ ๊ฐ์ ๋ ์์ง์ ๋ฌด์ํ๊ณ ๋ธ๋ผ์ฐ์ ์๊ฒ ์ง์ GPU ์์ ์ ๊ฑธ๊ธฐ ๋๋ฌธ.
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค: ์ด๊ฒ Children ํจํด ๋ง๋ฒ์ ๊ทผ์์
๋๋ค! ScrollAlphaHeader ๊ฐ ๋ฐฑ๋ ๋ด๋ถ ์ํ(opacity)๋ฅผ ๋ฐ๊พธ๋ฉฐ ํญ์ฃผ๊ธฐ๊ด์ฐจ์ฒ๋ผ ๋ฆฌ๋ ๋๋ง์ ๋์๋ดค์, ์๊ธฐํํ
์ ๊ฝํ์ง ํ๋ฒ๊ฑฐ ํจํฐ(children === <HeavyContent/>)๋ฅผ ๋๋ค์ ์๋ก ๋ง๋ค ๊ถํ์ ์์ต๋๋ค. ํจํฐ(๊ฐ์ฒด ์ฐธ์กฐ๊ฐ)๋ฅผ ๋ง๋ค์ด ๋๊ฒจ์ฃผ๋ ๋น์ฌ์๋ ๋ฐ๊นฅ์ชฝ์ธ Page ๋ถ๋ชจ ์ปดํฌ๋ํธ ์ด๋๊น์. Page ์
์ฅ์์ ์๋ฌด ์ํ ๋ณ์ด๊ฐ ์์ด ๊ฐ๋ง~ํ ๋ฉ์ถฐ์์ผ๋ ์ ๋ฌด๊ฑฐ์ด ์ปดํฌ๋ํธ ์ฃผ์ ๊ฐ์ฒด๋ ์์ ํฌ์ฅ์ง ๊ทธ๋๋ก ์ ์
๋๊ณ , ๋ฆฌ์กํธ ์์ง์ "์คํธ ํจํฐ ์์ ๊ฐ์ฒด๊ฐ ์ด์ ์ด๋ ๋๊ฐ์ ๋ ๊ป๋ฐ๊ธฐ๋ค? ๊ทธ๋ผ ์ฌํ์ฉ!" ํ๊ณ ํจ์คํด๋ฒ๋ฆฝ๋๋ค.
Q3. ์์ฒ ์ด๊ฐ React.memo ๋ฐฉ์ด๊ตฌ๋ฅผ ๋ก์น ํ๋ ๊ฒ์ ์ '๋์ ์ค๊ณ์ ๋ํ ์์ ๋ฐ์ฐฝ๊ณ '๋ผ๊ณ ๋นํ๋ฐ๋์ง, ๊ทธ ์์ ์จ๊ฒจ์ง ์ ์ง๋ณด์์์ ํญํ ๋๋ ๋ง(์์กด์ฑ ์ ํ ์ง์ฅ)๋ฅผ ์์ ํด ๋ณด์ธ์.
โ ์ ๋ต ๋ฐ ์ฃผ๊ด์ ํด์ค:
React.memo ๋ '๋ชจ๋ props๊ฐ ํ๋๋ ์ ๋ฐ๋์์ ๋'๋ง ์๋ํ๋ ๋งค์ฐ ์์ฝํ ๋ฐฉ์ด๋ง์ด๊ธฐ ๋๋ฌธ์
๋๋ค.
10๊ฐ์ ํ์ ์ปดํฌ๋ํธ๋ฅผ ์ ๋ถ Memo๋ก ๋ง์๋ค๊ณ ์๋ํ์ง๋ง, ๋ฏธ๋์ ๋๊ตฐ๊ฐ ๋ถ๋ชจ์์ ์์ฃผ ์ฌ์ํ { userInfo: {...} } ๊ฐ์ฒด ํ๋๋ onClose={() => {}} ํจ์ ํ๋๋ผ๋ ๋ณ์๊ฐ ์์ด ํ๋กญ์ค๋ก ์๋ก ๋์ง๋ ์๊ฐ, Memo์ ์์ ๋น๊ต๊ฐ ๋ฐ์ด ๋๋ฉฐ ํฌ๊ณผ ๋ฐ๋ฏธ์ง๊ฐ ๋ค์ด๊ฐ ํ์ ์ปดํฌ๋ํธ 10๊ฐ๊ฐ ๋๋ฏธ๋
ธ์ฒ๋ผ ์๋ฅด๋ฅด ๋ฌด๋์ ธ ๋ด๋ฆฝ๋๋ค.
์ด ํฌ๊ณผ ๋ฐ๋ฏธ์ง๋ฅผ ๋ง์ผ๋ ค๋ฉด ๋ ๋ถ๋ชจ๋ก ์ฌ๋ผ๊ฐ์ ๊ฐ์ฒด๋ useMemo๋ก ๋ฌถ๊ณ ํจ์๋ useCallback์ผ๋ก ๋ฌถ๋ ๋๋ฌผ๊ฒจ์ด '์ต์ ํ Hooks ์ง์ฅ'์ด ์ ์ผ๋ณ์ฒ๋ผ ๋ฒ์ง๊ฒ ๋ฉ๋๋ค. ์ ์ด์ ๊ตฌ์กฐ(children ๊ฒฉ๋ฆฌ, State push down)๋ก ๋ง์๋๋ผ๋ฉด ์ด๋ฐ์ ์ค๋ฒํค๋์ ๊ฑฐ์ง ๊ฐ์ ์ถ๊ฐ ์ฝ๋๋ค์ ๋จ ํ ์ค๋ ํ์๊ฐ ์๊ฒ ๋์ฃ .