React: Lifting State Up ๐๏ธโ๏ธ
React์์ ์ํ ๊ด๋ฆฌ์ ๊ธฐ๋ณธ ์์น ์ค ํ๋๋ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ์ ๋๋ค. ํ์ง๋ง ๋๋ก๋ ํ์ ์ปดํฌ๋ํธ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ํ์ฃ . ์ด๋ฐ ์ํฉ์์ ์ฌ์ฉ๋๋ ํจํด์ด ๋ฐ๋ก **Lifting State Up(์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ)**์ ๋๋ค. React ๊ณต์ ๋ฌธ์ Lifting State Up์ ๊ธฐ๋ฐ์ผ๋ก, ๋ ๋ง์ ์ค๋ช ๊ณผ ์ค์ ์์ ๋ฅผ ์ถ๊ฐํด ์์ธํ ๋ค๋ค๋ณด๊ฒ ์ต๋๋ค. ๐
Lifting State Up์ด๋?
React์์๋ **์ํ(state)**๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ปดํฌ๋ํธ ๋ด๋ถ์์ ๊ด๋ฆฌ๋ฉ๋๋ค. ํ์ง๋ง, ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๊ฑฐ๋ ์กฐ์ํด์ผ ํ ๋, ์ํ๋ฅผ ๊ฐ ์ปดํฌ๋ํธ์ ๋ถ์ฐ์ํค๋ ๋์ ๊ฐ์ฅ ๊ฐ๊น์ด ๊ณตํต ์์ ์ปดํฌ๋ํธ๋ก ๋์ด์ฌ๋ฆฌ๋ ๊ฒ์ด React์ ๊ถ์ฅ ๋ฐฉ์์ ๋๋ค.
์ ์ํ๋ฅผ ๋์ด์ฌ๋ฆด๊น?
• ๋ฐ์ดํฐ ๋๊ธฐํ: ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํด์ผ ํ ๋, ์์ ์ปดํฌ๋ํธ์์ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ฉด ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
• ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ: React๋ ๋ถ๋ชจ์์ ์์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ๋จ๋ฐฉํฅ ํ๋ฆ์ ๊ฐ์กฐํฉ๋๋ค. ์ํ๋ฅผ ๋์ด์ฌ๋ฆฌ๋ฉด ์ด ์์น์ ์ ์งํ๋ฉด์ ๋ฐ์ดํฐ ํ๋ฆ์ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค.
Lifting State Up์ ๊ธฐ๋ณธ ์๋ฆฌ
์์ : ๋ ์ ๋ ฅ๊ฐ์ ๋๊ธฐํํ๋ ์จ๋ ๋ณํ๊ธฐ ๋ง๋ค๊ธฐ
React ๊ณต์ ๋ฌธ์์ ๊ฐ๋จํ ์์ ์ธ ์จ๋ ๋ณํ๊ธฐ๋ฅผ ํ์ฅํด ๋ณด๊ฒ ์ต๋๋ค.
1๏ธโฃ ์ปดํฌ๋ํธ๋ณ ์ญํ ๋ถ๋ฆฌ
• BoilingVerdict: ์จ๋๊ฐ 100°C ์ด์์ผ ๋ ๋ฌผ์ด ๋๋์ง ์ฌ๋ถ๋ฅผ ํ์ํฉ๋๋ค.
• TemperatureInput: ์จ๋๋ฅผ ์ ๋ ฅ๋ฐ๋ ์ปดํฌ๋ํธ์ ๋๋ค.
• Calculator: ์ํ๋ฅผ ๋์ด์ฌ๋ ค ๋ TemperatureInput ์ปดํฌ๋ํธ๋ฅผ ๋๊ธฐํํฉ๋๋ค.
์ด๊ธฐ ๊ตฌํ ์ฝ๋
function BoilingVerdict({ celsius }) {
return celsius >= 100 ? <p>๋ฌผ์ด ๋์ด์!</p> : <p>๋ฌผ์ด ๋์ง ์์์.</p>;
}
function TemperatureInput({ scale, temperature, onTemperatureChange }) {
const scaleNames = { c: "์ญ์จ", f: "ํ์จ" };
return (
<fieldset>
<legend>์จ๋๋ฅผ ์ ๋ ฅํ์ธ์ (๋จ์: {scaleNames[scale]})</legend>
<input
value={temperature}
onChange={(e) => onTemperatureChange(e.target.value)}
/>
</fieldset>
);
}
function Calculator() {
const [temperature, setTemperature] = React.useState("");
const [scale, setScale] = React.useState("c");
const handleCelsiusChange = (temp) => {
setScale("c");
setTemperature(temp);
};
const handleFahrenheitChange = (temp) => {
setScale("f");
setTemperature(temp);
};
const tryConvert = (temp, convert) => {
const input = parseFloat(temp);
if (Number.isNaN(input)) return "";
return (Math.round(convert(input) * 1000) / 1000).toString();
};
const celsius =
scale === "f" ? tryConvert(temperature, (f) => ((f - 32) * 5) / 9) : temperature;
const fahrenheit =
scale === "c" ? tryConvert(temperature, (c) => (c * 9) / 5 + 32) : temperature;
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius}
onTemperatureChange={handleCelsiusChange}
/>
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={handleFahrenheitChange}
/>
<BoilingVerdict celsius={parseFloat(celsius)} />
</div>
);
}
๋์ ๋ฐฉ์
• Calculator์์ ์ํ(temperature, scale)๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
• ์ํ ๋ณ๊ฒฝ ํธ๋ค๋ฌ๋ฅผ props๋ก ์ ๋ฌํ์ฌ TemperatureInput์ด ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ์ ์๊ฒ ํฉ๋๋ค.
• ์ ๋ ฅ๊ฐ์ ์๋ก ๋๊ธฐํ๋๊ณ , BoilingVerdict๋ ์ ๋ฐ์ดํธ๋ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ์ ํ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค.
์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ์ ์ฅ๋จ์
โ ์ฅ์
1. ๋ฐ์ดํฐ ์ผ๊ด์ฑ: ๊ณตํต๋ ์ํ๋ฅผ ์์ ์ปดํฌ๋ํธ์์ ๊ด๋ฆฌํด ์ฌ๋ฌ ์ปดํฌ๋ํธ ๊ฐ์ ๋ฐ์ดํฐ ๋ถ์ผ์น๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
2. ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ ์ ์ง: React์ ํต์ฌ ์ฒ ํ์ธ ๋ฐ์ดํฐ ํ๋ฆ์ ๋จ์ํ๊ณ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค.
3. ์ ์ง๋ณด์์ฑ ์ฆ๊ฐ: ์ํ ๊ด๋ฆฌ์ ๋น์ฆ๋์ค ๋ก์ง์ด ํ ๊ณณ์ ๋ชจ์ด๋ฏ๋ก ์ฝ๋๊ฐ ๋ ์ง๊ด์ ์ ๋๋ค.
โ ๋จ์
1. ์์ ์ปดํฌ๋ํธ๊ฐ ๋น๋ํด์ง: ์ํ์ ๋ก์ง์ด ๋ง์์ง์๋ก ์์ ์ปดํฌ๋ํธ๊ฐ ๋ณต์กํด์ง ์ ์์ต๋๋ค.
2. ์ค์ฒฉ๋ ๊ตฌ์กฐ์์์ ์ด๋ ค์: ์ํ๋ฅผ ๋๋ฌด ๋ง์ด ๋์ด์ฌ๋ฆฌ๋ฉด ๊น๊ฒ ์ค์ฒฉ๋ ์ปดํฌ๋ํธ์์ props๋ฅผ ์ ๋ฌํ๋ ๊ณผ์ ์ด ๊ธธ์ด์ง ์ ์์ต๋๋ค.
์ถ๊ฐ: Context์ ์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ์ ์กฐํ
์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ๋ง์ผ๋ก๋ ๋ชจ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ด๋ ต์ต๋๋ค. React Context๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์ญ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ฉด์ ์์ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ์ ์งํ ์ ์์ต๋๋ค.
์์ : Context๋ก ์ํ ๊ณต์ ํ๊ธฐ
const TemperatureContext = React.createContext();
function TemperatureProvider({ children }) {
const [temperature, setTemperature] = React.useState("");
const [scale, setScale] = React.useState("c");
const contextValue = {
temperature,
scale,
setTemperature,
setScale,
};
return (
<TemperatureContext.Provider value={contextValue}>
{children}
</TemperatureContext.Provider>
);
}
function TemperatureInputWithContext({ scale }) {
const { temperature, scale: currentScale, setTemperature, setScale } =
React.useContext(TemperatureContext);
const handleChange = (temp) => {
setScale(scale);
setTemperature(temp);
};
const value =
scale === "c"
? currentScale === "f"
? ((temperature - 32) * 5) / 9
: temperature
: currentScale === "c"
? temperature * 9 / 5 + 32
: temperature;
return (
<fieldset>
<legend>์จ๋๋ฅผ ์ ๋ ฅํ์ธ์ (๋จ์: {scale === "c" ? "์ญ์จ" : "ํ์จ"})</legend>
<input
value={value}
onChange={(e) => handleChange(e.target.value)}
/>
</fieldset>
);
}
function App() {
return (
<TemperatureProvider>
<TemperatureInputWithContext scale="c" />
<TemperatureInputWithContext scale="f" />
</TemperatureProvider>
);
}
๊ฒฐ๋ก
์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ๋ React์์ ์ปดํฌ๋ํธ ๊ฐ ๋ฐ์ดํฐ ๊ณต์ ๋ฅผ ์ํ ๊ธฐ๋ณธ์ ์ด๋ฉด์ ๊ฐ๋ ฅํ ํจํด์ ๋๋ค.
• ๊ฐ๋จํ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ๋ง์ผ๋ก ์ถฉ๋ถํ์ง๋ง,
• Context API ๋๋ ์ ์ญ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(e.g., Redux, Zustand)๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋ณต์กํ ์ฑ์์๋ ํจ์จ์ ์ผ๋ก ์ํ๋ฅผ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
๐ท์ ์ค์ ๊ฐ๋ฐ์๊ฐ ๋์ด๋ด ์๋น!๐ท
'Front-end > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
MDX: Markdown๊ณผ React์ ์๋ฆ๋ค์ด ๋ง๋จ โจ (1) | 2025.03.01 |
---|---|
[React] Render Props: ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ์ฑ์ ํ ๋จ๊ณ ์ ๊ทธ๋ ์ด๋ํ๊ธฐ ๐จ (0) | 2025.02.25 |
React์ Composition vs Inheritance ๐ (0) | 2025.02.22 |
๐ React์ Lazy Loading: ๋ก๋ฉ ์ฑ๋ฅ ์ต์ ํ์ ๋น๋ฐ ๐ (0) | 2025.02.18 |
React์ Link ์ปดํฌ๋ํธ vs. ์ ํต์ ์ธ <a> ํ๊ทธ: ๋ญ๊ฐ ๋ค๋ฅผ๊น? (1) | 2025.02.13 |