basic ๋ฐฐํฌ ๊ฒฝ๋ก advanced ๋ฐฐํฌ ๊ฒฝ๋ก
- React์ hook ์ดํดํ๊ธฐ
- ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๋ํ ์ดํด
- ์ก์ ๊ณผ ์์ํจ์์ ๋ถ๋ฆฌ
- ์ํฐํฐ๋ฅผ ๋ค๋ฃจ๋ ์ํ์ ๊ทธ๋ ์ง ์์ ์ํ - cart, isCartFull vs isShowPopup
- ์ํฐํฐ๋ฅผ ๋ค๋ฃจ๋ ์ปดํฌ๋ํธ์ ํ - CartItemView, useCart(), useProduct()
- ์ํฐํฐ๋ฅผ ๋ค๋ฃจ์ง ์๋ ์ปดํฌ๋ํธ์ ํ - Button, useRoute, useEvent ๋ฑ
- ์ํฐํฐ๋ฅผ ๋ค๋ฃจ๋ ํจ์์ ๊ทธ๋ ์ง ์์ ํจ์ - calculateCartTotal(cart) vs capaitalize(str)
-
Component์์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ถ๋ฆฌํ๊ธฐ
-
๋น์ฆ๋์ค ๋ก์ง์์ ํน์ ์ํฐํฐ๋ง ๋ค๋ฃจ๋ ๊ณ์ฐ์ ๋ถ๋ฆฌํ๊ธฐ
-
๋ทฐ๋ฐ์ดํฐ์ ์ํฐํฐ๋ฐ์ดํฐ์ ๋ถ๋ฆฌ์ ๋ํ ์ดํด
-
entities -> features -> UI ๊ณ์ธต์ ๋ํ ์ดํด
-
Component์์ ์ฌ์ฉ๋๋ Data๊ฐ ์๋ ๋ก์ง๋ค์ hook์ผ๋ก ์ฎ๊ฒจ์ก๋์?
-
์ฃผ์ด์ง hook์ ์ฑ ์์ ๋ง๋๋ก ์ฝ๋๊ฐ ๋ถ๋ฆฌ๊ฐ ๋์๋์?
-
๊ณ์ฐํจ์๋ ์์ํจ์๋ก ์์ฑ์ด ๋์๋์?
-
Component์์ ์ฌ์ฉ๋๋ Data๊ฐ ์๋ ๋ก์ง๋ค์ hook์ผ๋ก ์ฎ๊ฒจ์ก๋์?
-
์ฃผ์ด์ง hook์ ์ฑ ์์ ๋ง๋๋ก ์ฝ๋๊ฐ ๋ถ๋ฆฌ๊ฐ ๋์๋์?
-
๊ณ์ฐํจ์๋ ์์ํจ์๋ก ์์ฑ์ด ๋์๋์?
-
ํน์ Entitiy๋ง ๋ค๋ฃจ๋ ํจ์๋ ๋ถ๋ฆฌ๋์ด ์๋์?
-
ํน์ Entitiy๋ง ๋ค๋ฃจ๋ Component์ UI๋ฅผ ๋ค๋ฃจ๋ Component๋ ๋ถ๋ฆฌ๋์ด ์๋์?
-
๋ฐ์ดํฐ ํ๋ฆ์ ๋ง๋ ๊ณ์ธต๊ตฌ์กฐ๋ฅผ ์ด๋ฃจ๊ณ ์์กด์ฑ์ด ๋ง๊ฒ ์์ฑ์ด ๋์๋์?
-
์ด๋ฒ ์ฌํ๊ณผ์ ๋ Context๋ Jotai๋ฅผ ์ฌ์ฉํด์ Props drilling์ ์์ ๋ ๊ฒ์ ๋๋ค.
-
์ด๋ค props๋ ๋จ๊ฒจ์ผ ํ๋์ง, ์ด๋ค props๋ ์ ๊ฑฐํด์ผ ํ๋์ง์ ๋ํ ๊ธฐ์ค์ ์ธ์๋ณด์ธ์.
-
Context๋ Jotai๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ตํ๊ณ , ์ด๋ฅผ ํตํด ์ปดํฌ๋ํธ ๊ฐ์ ๋ฐ์ดํฐ ์ ๋ฌ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
-
Context๋ Jotai๋ฅผ ์ฌ์ฉํด์ ์ ์ญ์ํ๊ด๋ฆฌ๋ฅผ ๊ตฌ์ถํ๋์?
-
์ ์ญ์ํ๊ด๋ฆฌ๋ฅผ ํตํด domain custom hook์ ์ ์ ํ๊ฒ ๋ฆฌํฉํ ๋ง ํ๋์?
-
๋๋ฉ์ธ ์ปดํฌ๋ํธ์ ๋๋ฉ์ธ props๋ ๋จ๊ธฐ๊ณ props drilling์ ์ ๋ฐํ๋ ๋ถํ์ํ props๋ ์ ์ ๊ฑฐํ๋์?
-
์ ์ฒด์ ์ผ๋ก ๋ถ๋ฆฌ์ ์ฌ์กฐ๋ฆฝ์ด ๋ ์์ํด์ง ๊ฒฐํฉ๋๊ฐ ๋ฎ์์ง ์ฝ๋๊ฐ ๋์๋์?
ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์ฌ์ค์ ํ๋ก๊ทธ๋๋ฐ ์ฒ ํ์ ๊ฐ๊น์ด ๊ฐ๋ ์ผ๋ก, ํ ๋ฌธ์ฅ์ผ๋ก ๋งํ์๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
๋ฐ์ดํฐ๋ ๋ณํ์ง ์์ผ๋ฉฐ, ํ๋ก๊ทธ๋จ์ ์์ ํจ์๋ค์ ์กฐํฉ์ผ๋ก ๊ตฌ์ฑ๋๋ค.
(1) ๋ฐ์ดํฐ๋ ๋ณํ์ง ์๋๋ค(Immutability) ๊ฐ์ฒด๋ ๋ฐฐ์ด์ ๊ฐ์ ์ง์ ๋ฐ๊พธ๋ ๋์ , ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์ด๋ด์ผ ํฉ๋๋ค. ๊ทธ๋ ๊ฒ ๊ฐ์กฐํด๋๋ ๋ถ๋ณ์ฑ์ ๊ฐ๋ ์ธ๋ฐ ๊ฒฐ๊ตญ ์ํ๊ฐ ์ธ์ ๋ฐ๋์๋์ง ๋ช ํํด์ผ ๋ ๋๋ง ํด์ ํ๋ ๋ณ๊ฒฝ ์ถ์ ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ๊ฐ์กฐํ๋ ๊ฒ์ ๋๋ค.
๐ง ์ ๊ทธ๋์ผ ํ ๊น์?
- ๊ฐ์ด ์ค๊ฐ์ ๋ฐ๋์ง ์์ผ๋ ์์ธก ๊ฐ๋ฅ์ฑ์ด ๋์์ง๊ณ
- ๋๋ฒ๊น ์ด ์ฌ์์ง๊ณ
- ๋์์ฑ ๋ฌธ์ (๋ฉํฐ ์ค๋ ๋, ๋น๋๊ธฐ)์์ ์ถฉ๋์ด ์ค์ด๋ค๊ณ
- ์ํ๋ฅผ ๋๋๋ฆฌ๊ฑฐ๋ ์๊ฐ ์ฌํ ๋๋ฒ๊น (Time-travel debugging)์ด ๊ฐ๋ฅํด์ง๊ธฐ ๋๋ฌธ์ ๋๋ค.
(2) ์์ ํจ์๋ก ๊ตฌ์ฑํ๋ค(Pure Function) ์์ ํจ์๊ฐ ๋ฌด์์ผ๊น์? ์๋๋ง ๊ธฐ์ตํฉ์๋ค!
- ๊ฐ์ ์ ๋ ฅ โ ํญ์ ๊ฐ์ ์ถ๋ ฅ
- ํจ์ ์ธ๋ถ ์ํ๋ฅผ ๋ณ๊ฒฝํ์ง ์์
function pureAdd(a, b) {
return a + b; // ๊ฐ์ ์
๋ ฅ โ ๊ฐ์ ๊ฒฐ๊ณผ
}
function impureAdd(a, b) {
console.log("์คํ๋จ"); // ์ธ๋ถ ์ํ ์ฌ์ฉ (์ฝ์)
return a + b;
}๊ทผ๋ฐ ์ ๋ฐ util ํจ์ ๋จ๊ณ์ ๋๋ฉด ์ถฉ์กฑํ๊ธฐ ์ฝ์ง๋ง ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ๋ฑ์ ๋ณต์กํ ๋ก์ง์์๋ ๊ทธ๊ฒ ์ด๋ป๊ฒ ๊ฐ๋ฅํ ๊น์?
FP์์ ๋งํ๊ณ ์ ํ๋ ๋ฐ๋ ๋ชจ๋ ๊ฑธ ์์ํจ์๋ก ๋ง๋ค๋ผ๋ ๊ฒ์ด ์๋๋๋ค. ์์ํจ์๋ฅผ ์ต๋ํํ๊ณ ๋ถ์ํจ๊ณผ๋ ์๋๋ ์์น์ ๋ชจ์๋์ด ๋ณ๊ฒฝ ๋ฐ ๊ด๋ฆฌ๊ฐ ์ฉ์ดํ๋๋ก ํ๋ฉด ๋ฉ๋๋ค.
(3) ํจ์๋ ์กฐํฉ ๊ฐ๋ฅํ ์์ ๋ธ๋ก์ด๋ค(Composition) ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์์๋ ํฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํจ์๋ฅผ ๊ณ์ ํฉ์ฑ(์กฐํฉ)ํด ๋๊ฐ๋ ๋ฐฉ์์ ์ ํธํฉ๋๋ค.
const double = x => x * 2;
const inc = x => x + 1;
const process = x => double(inc(x));
process(3); // 8์ด๊ฑธ FP์์๋ ํจ์ ํฉ์ฑ์ด๋ผ๊ณ ํ๋ฉฐ, ๋ ๊ณ ๋ธ๋ญ ์๋ฏ์ด ์์ ๋จ์๋ก ์ชผ๊ฐ์ ์กฐํฉํ๋ ๊ฑธ ์๋ฏธํฉ๋๋ค.
์ด๋ฆ์์๋ถํฐ ๋ช ๋ นํ ํ๋ก๊ทธ๋๋ฐ์ ์ด๋ ๊ฒ ํด! ํ๊ณ ์ด๋ป๊ฒ(how) ํ ์ง๋ฅผ ์ค๋ช ํ๋ค๋ฉด, ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํจ์๊ฐ ์ธ์๋ฅผ ๋ฐ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋๋ ค์ฃผ๋ฏ์ด ์ด๋ค ๊ฒฐ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์ํด ๋ฌด์(what)์ ํ ์ง๋ฅผ ์ค๋ช ํฉ๋๋ค.
// ๋ช
๋ นํ: ์ด๋ป๊ฒ ๋ฐ๋ณตํ ์ง ์๋ ค์ค
let result = [];
for (let n of numbers) {
result.push(n * 2);
}
// ์ ์ธํ: ๋ฌด์์ ํ ์ง ๋งํจ
numbers.map(n => n * 2);ํด๋ ๊ตฌ์กฐ๋ ํ์ผ๋ช ์์ ์์ฃผ ์ฌ์ฉ๋๋ ์ํฐํฐ(Entity)๋ผ๋ ์ฉ์ด๊ฐ ์๋๋ฐ ์ ํํ ๋ฌด์จ ๋ป์ผ๊น์?
**์ํฐํฐ(Entity)**๋ ๋๋ฉ์ธ(๋น์ฆ๋์ค ๋ก์ง)์ ํต์ฌ์ด ๋๋ ์ค์ ๋ฐ์ดํฐ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ฉฐ, ์ฝ๊ฒ ๋งํด ์ฑ์ด ๋ค๋ฃจ๋ โ์ง์ง ๋์โ์ ๋งํฉ๋๋ค.
์ด ์ํฐํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก Component, hook, function์ ๋๋ ์ ์์ต๋๋ค.
- ์ํฐํฐ๋ฅผ ๋ค๋ฃจ๋ ์ํ์ ๊ทธ๋ ์ง ์์ ์ํ - cart, isCartFull vs isShowPopup
- ์ํฐํฐ๋ฅผ ๋ค๋ฃจ๋ ์ปดํฌ๋ํธ์ ํ - CartItemView, useCart(), useProduct()
- ์ํฐํฐ๋ฅผ ๋ค๋ฃจ์ง ์๋ ์ปดํฌ๋ํธ์ ํ - Button, useRoute, useEvent ๋ฑ
- ์ํฐํฐ๋ฅผ ๋ค๋ฃจ๋ ํจ์์ ๊ทธ๋ ์ง ์์ ํจ์ - calculateCartTotal(cart) vs capaitalize(str)
์ Entity๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ถ๋ฆฌ๋ฅผ ํด์ผ ํ๋๊ฑธ๊น์? ์ง๊ธ ๊ณผ์ ๋ฅผ ๊ธฐ์ค์ผ๋ก ์๊ฐํด๋ด ์๋ค.
๊ณผ์ ๋ ์ผํ๋ชฐ ํ๋ก์ ํธ์ด๊ณ ํด๋น ํ๋ก์ ํธ์์ ๋ค๋ค์ง๋ ๊ฐ์ฒด(data)์๋ ํฌ๊ฒ ์ํ, ์ฟ ํฐ, ์ฅ๋ฐ๊ตฌ๋๊ฐ ์์ต๋๋ค. ์ฌ๊ธฐ์ ์๊ฐํ ์ ์๋ ๊ตฌ์กฐ๋ก๋ ์ํ ์นด๋, ์ฟ ํฐ ์นด๋, ์ฅ๋ฐ๊ตฌ๋ ์์ดํ ์นด๋๊ฐ ๋ํ์ ์ผ๋ก ์๊ฒ ์ฃ .
๋ง์ฝ ๊ทน๋จ์ ์ผ๋ก ์ด ์์ดํ ์นด๋๋ฅผ ํ๋์ ์ปดํฌ๋ํธ๋ก ๋ ๋ํ๊ฒ๋ ํ๋ค๋ฉด ํ ์ปดํฌ๋ํธ ๋ด์์ ๋ถ๊ธฐ๋ฅผ ์ถ๊ฐํ๋ฉด์ ๋ ๋ํ๊ฒ๋ ํ ๊ฒ์ ๋๋ค.
๊ทธ๋ผ ๋ฌธ์ ์๋ ๊ฑฐ ์๋๊ฐ์?๐ค ๋ช๊ฐ์ ๋ค ์์ดํ ์นด๋์ ์๋ก์ด ๊ฐ์ฒด์ธ ๊ฒ์๊ธ์ด ์ถ๊ฐ๋์ด์ผ ํ๋ค๊ณ ํ ๋ ์ปดํฌ๋ํธ ๋ด์ ๋ถ๊ธฐ๋ฅผ ์ถ๊ฐํด์ผ ํ๊ณ ์ด๋ ๊ณง ๋ค๋ฅธ ๋ถ๊ธฐ์๋ ์ํฅ์ ์ค ์ ์๋ ์ ์ฌ์ ์ํ์ด ๋ฉ๋๋ค.
์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์๋ ์ฐ๋ฆฌ๋ ๊ฐ ๊ฐ์ฒด๋ณ๋ก ๋ค๋ฅธ ๊ด์ฌ์ฌ๋ฅผ ๊ฒฉ๋ฆฌ์ํค๊ณ ๋ ๋ฆฝ์ ์ผ๋ก ํ์ฅํด๋๊ฐ ์ ์๋๋ก ๋ณด์ฅํด์ค์ผ ํฉ๋๋ค.
์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก๋ Zustand๋ฅผ ์ฌ์ฉํด๋ดค๋๋ฐ Jotai๋ ์ฒ์ ์ ํด๋ดค์ต๋๋ค. (Jotai ์กฐํ..) Jotai๋ React์ ์ ์ฌํ ๋ฌธ๋ฒ ์ฒด๊ณ๋ฅผ ๊ฐ์ง๊ณ ์์ด React์ ํนํ๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
์ผ๋ง๋ ๋น์ทํ๊ธธ๋..?ํ๊ณ ๋ณด๋ฉด ์ง์ง ๊ฑฐ์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ๊ธ์ด๋ค์
// 1. React์ useState๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
// 2. Jotai์ useAtom์ ์ฌ์ฉํ ๊ฒฝ์ฐ
import { atom, useAtom } from 'jotai';
// ์ปดํฌ๋ํธ ๋ฐ์ atom(์ํ์ ๋จ์)์ ์ ์ํฉ๋๋ค
const countAtom = atom(0);
function Counter() {
// useState์ ์ฌ์ฉ๋ฒ์ด ์์ ํ ๋์ผํฉ๋๋ค!
const [count, setCount] = useAtom(countAtom);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}์ด๋งํผ ์ ์ฌํ ๋ฌธ๋ฒ ์ฒด๊ณ๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด React ํ๋ก์ ํธ์์ ์ ์ญ ์ํ๊ด๋ฆฌ๋ฅผ ๋์ ํด์ผ ํ๋ค๋ฉด, ๋ฌ๋์ปค๋ธ๋ ์ ๊ณ ์ ํ ์๊ฐ์ ์ต์ํํ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค.
(1) ๊ฐ๋ ์ ๋ฆฝ ํด๋น ์ฑํฐ์์ ๋ค๋ฃจ๋ ๋์์ธ ํจํด๊ณผ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๋ํด ์ดํดํ๊ณ ์ ๋ฆฌํ๋ ์๊ฐ์ ๊ฐ์ก์ต๋๋ค.
(2) ๊ตฌ์กฐ์ ์๊ฐํ ๊ทธ๋ฆฌ๊ณ ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ์๊ฐํํ๊ธฐ๋ก ๊ฒฐ์ฌํ์ต๋๋ค.
๋ฉํ ๋ง์์ ๊ตฌ์กฐ๋ฅผ ์๊ฐํํ๋ ์ฐ์ต์ ํด๋ณด๋ผ๊ณ ํ์ จ๋ ์กฐ์ธ๊ณผ ๋๋ถ์ด ์ด๋ฒ ๊ณผ์ ์ ํต์ฌ์ ์๋ ๊ตฌ์กฐ์ ๋ฌธ์ ์ ์ ํ์ ํ๊ณ ์ด๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํด ์ด๋ค ํจํด์ ์ ์ฉํ ์ง, ์ด๋ป๊ฒ ๋ฆฌํฉํ ๋งํ ์ง๋ฅผ ์ฌ๊ณ ํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
(2-1) ํ ์คํธ๋ก ๊ธฐ๋ฅ ์ ๋ฆฌ ์ฒ์๋ถํฐ ์ฝ๋๋ฅผ ๋ณด๋ฉด์ ๋ชจ๋ ๊ธฐ๋ฅ์ ์ ๋ฆฌํ๋ ค ํ๋ฉด ๋ณต์กํ ๊ฒ ๊ฐ์์ ๋น๋ํ ํ์ด์ง์ ์ง์ ์ก์ ์ ํด๋ณด๋ฉฐ ๊ธฐ๋ฅ์ค๊ณ์๋ฅผ ์ญ์ผ๋ก ์์ฑํ๊ณ ํน์ ๋๋ฝํ๊ฑฐ๋ ์๋ชป ์์ฑํ ๋ถ๋ถ์ด ์์๊น๋ด AI์๊ฒ ๊ฒ์ฆ์ ๋งก๊ฒผ์ต๋๋ค.
# ์ผํ๋ชฐ
- ์ผํ๋ชฐ์ ์กด์ฌํ๋ ์ํ ๋ชฉ๋ก์ด ๋
ธ์ถ๋๋ค.
- ์ฌ๊ณ ๊ฐ 5๊ฐ ์ดํ๋ฉด ํ์ ์๋ฐ ํ
์คํธ๊ฐ ๋
ธ์ถ๋๋ค.
- ํ ์ธ์ด ์์ ๊ฒฝ์ฐ ํด๋น ํ ์ธ ์ ๋ณด๋ฅผ ๋
ธ์ถํ๋ค.
- ์ฌ๊ณ ์์ง ์ ํ์ ๋ฒํผ์ผ๋ก ๋ณ๊ฒฝ & ๊ฐ๊ฒฉ ์์ญ์ด SOLD OUT์ผ๋ก ๋ณ๊ฒฝ๋๋ค.
- ๊ฒ์ input ์
๋ ฅ โ ํด๋น input๊ฐ์ ํฌํจํ๋ ์ํ๋ค์ ๋ฐํํ๋ค.
- ๊ฒ์์ด ์
๋ ฅ ํ 500ms ์ง์ฐ ํ ๊ฒ์์ด ์คํ๋๋ค. (debounce)
- ์ํ๋ช
๊ณผ ์ํ ์ค๋ช
๋ชจ๋์์ ๊ฒ์ํ๋ค.
- ํฌํจํ๋ ์ํ์ด ์์ผ๋ฉด empty UI๋ฅผ ๋ฐํํ๋ค.
- ๋น ๊ฐ์ด๋ฉด ์ ์ฒด ์ํ ๋ฆฌ์คํธ๋ฅผ ๋ฐํํ๋ค.
- ์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ ๋ฒํผ ํด๋ฆญ โ ์ฅ๋ฐ๊ตฌ๋์ ํด๋น ์ํ์ด ๋ด๊ธด๋ค.
- ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (3์ด ํ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ค)
- ์ฐ์ธก์ ํด๋น ์ํ์ด ์ ์ฉ๋๋ค.
- ํค๋์ ์ฅ๋ฐ๊ตฌ๋ ์์ด์ฝ ์์ ์ด ์์ดํ
๊ฐ์๊ฐ ๋ฐฐ์ง๋ก ํ์๋๋ค.
- ์๋ input ํด๋ฆญ โ ์ฅ๋ฐ๊ตฌ๋์ ๋ด์ ์ํ ์๊ฐ 1์ฉ ์ฆ๊ฐํ๋ค.
- ์ง์ ๊ฐ์ ์ด์์ด๋ฉด ์ง์ ํ ํ ์ธ์จ์ด ์ ์ฉ๋๋ค.
- ์ฅ๋ฐ๊ตฌ๋์ 10๊ฐ ์ด์์ธ ์ํ์ด ์์ผ๋ฉด ์ถ๊ฐ 5% ํ ์ธ์ด ์ ์ฉ๋๋ค. (์ต๋ 50%๊น์ง)
- ์ฌ๊ณ ์ด์์ผ๋ก ์ฆ๊ฐํ ๊ฒฝ์ฐ, ์๋ ์๋ฌ ํ ์คํธ ํ์
์ด ๋ฌ๋ค.
- 1์์ 0์ผ๋ก ๊ฐ์ํ ๊ฒฝ์ฐ, ์ฅ๋ฐ๊ตฌ๋์ ํด๋น ์ํ์ด ์ ๊ฑฐ๋๋ค.
- ์ฌ๊ณ ์์ง ์ ํ์ ๋ฒํผ์ผ๋ก ๋ณ๊ฒฝ & ๊ฐ๊ฒฉ ์์ญ์ด SOLD OUT์ผ๋ก ๋ณ๊ฒฝ๋๋ค.
- ๊ฐ ์ฅ๋ฐ๊ตฌ๋ ์์ดํ
์ ์ ์ฉ๋ ํ ์ธ์จ์ด "-X%" ํํ๋ก ํ์๋๋ค.
- ์ฟ ํฐ select ํด๋ฆญ โ ์ ํํ ๊ฐ์ผ๋ก ์ฟ ํฐ ํ ์ธ์ด ์ ์ฉ๋๋ค.
- ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (3์ด ํ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ค)
- ์ ์ฉ ๋ถ๊ฐํ ์ฟ ํฐ์ผ ๊ฒฝ์ฐ, ์๋ฌ ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (percentage ์ฟ ํฐ์ 10,000์ ์ด์ ๊ตฌ๋งค ์ ์ฌ์ฉ ๊ฐ๋ฅ)
- ๊ฒฐ์ ๋ฒํผ ํด๋ฆญ โ ๊ฒฐ์ ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค.
- ์ฅ๋ฐ๊ตฌ๋์ ํด๋น ์ํ์ด ์ ๊ฑฐ๋๋ค.
- ์ ํ๋ ์ฟ ํฐ์ด ํด์ ๋๋ค.
- ์ฅ๋ฐ๊ตฌ๋ X ๋ฒํผ ํด๋ฆญ โ ์ฅ๋ฐ๊ตฌ๋์ ํด๋น ์ํ์ด ์ ๊ฑฐ๋๋ค.
- ๊ด๋ฆฌ์ ํ์ด์ง๋ก ๋ฒํผ ํด๋ฆญ โ ๊ด๋ฆฌ์ ํ์ด์ง๋ก ์ด๋ํ๋ค.
- ๋ฐ์ดํฐ ์ ์ฅ/๋ณต์
- ์ํ, ์ฟ ํฐ, ์ฅ๋ฐ๊ตฌ๋ ๋ฐ์ดํฐ๊ฐ localStorage์ ์๋์ผ๋ก ์ ์ฅ๋๋ค.
- ํ์ด์ง ์๋ก๊ณ ์นจ ์ ์ ์ฅ๋ ๋ฐ์ดํฐ๊ฐ ์๋์ผ๋ก ๋ณต์๋๋ค.
# ๊ด๋ฆฌ์
- ์ ์ํ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ์ ์ํ ์ถ๊ฐ form์ด ๋
ธ์ถ๋๋ค.
- ์ํ๋ช
์ ์
๋ ฅํ์ง ์๊ณ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ๊ฐ๊ฒฉ์ ์
๋ ฅํ์ง ์๊ณ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ๋ฌธ์์ด ์
๋ ฅ โ ์๋ฌด์ผ๋ ์ผ์ด๋์ง ์๋๋ค. (์ซ์๋ง ์
๋ ฅ ๊ฐ๋ฅ)
- ์ฌ๊ณ ๋ฅผ ์
๋ ฅํ์ง ์๊ณ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ๋ฌธ์์ด ์
๋ ฅ โ ์๋ฌด์ผ๋ ์ผ์ด๋์ง ์๋๋ค. (์ซ์๋ง ์
๋ ฅ ๊ฐ๋ฅ)
- ์ทจ์ ๋ฒํผ ํด๋ฆญ โ ์ ์ํ ์ถ๊ฐ form์ด ๋ฏธ๋
ธ์ถ๋๋ค.
- ํ ์ธ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ํ ์ธ ์ถ๊ฐ form์ด ๋
ธ์ถ๋๋ค. (๊ธฐ๋ณธ: 10๊ฐ | 10%)
- ํ ์ธ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ํ ์ธ ์ถ๊ฐ form์ด ์ถ๊ฐ๋๋ค.
- ํ ์ธ ์๋ input์ type="number"์ด๋ฉฐ min="1" ์์ฑ์ด ์์ด 0 ์ดํ ์
๋ ฅ ์ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation์ด ์๋ํ๋ค.
- ํ ์ธ์จ input์ type="number"์ด๋ฉฐ max="100" ์์ฑ์ด ์์ด 100 ์ด์ ์
๋ ฅ ์ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation์ด ์๋ํ๋ค.
- ๊ฐ ํ ์ธ ํญ๋ชฉ์ X ๋ฒํผ ํด๋ฆญ โ ํด๋น ํ ์ธ ํญ๋ชฉ์ด ์ญ์ ๋๋ค.
- ํ์๊ฐ(์ํ๋ช
, ๊ฐ๊ฒฉ, ์ฌ๊ณ )์ ์
๋ ฅํ๊ณ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ์ํ ๋ชฉ๋ก์ ์ถ๊ฐ๋๋ค.
- ์ ์ํ ์ถ๊ฐ form์ด ๋ฏธ๋
ธ์ถ๋๋ค.
- ์ํ ์ถ๊ฐ ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (3์ด ํ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ค)
- ์ญ์ ๋ฒํผ ํด๋ฆญ โ ํด๋น ์ํ์ด ์ญ์ ๋๋ค.
- ์ญ์ ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (3์ด ํ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ค)
- ์์ ๋ฒํผ ํด๋ฆญ โ ์ํ ์์ form์ด ๋
ธ์ถ๋๋ค.
- ์์ ๋ฒํผ ํด๋ฆญ โ ์์ ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (3์ด ํ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ค)
- ์ํ๋ช
์ ์
๋ ฅํ์ง ์๊ณ ์์ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ๊ฐ๊ฒฉ์ ์
๋ ฅํ์ง ์๊ณ ์์ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ๋ฌธ์์ด ์
๋ ฅ โ ์๋ฌด์ผ๋ ์ผ์ด๋์ง ์๋๋ค. (์ซ์๋ง ์
๋ ฅ ๊ฐ๋ฅ)
- ์ฌ๊ณ ๋ฅผ ์
๋ ฅํ์ง ์๊ณ ์์ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ๋ฌธ์์ด ์
๋ ฅ โ ์๋ฌด์ผ๋ ์ผ์ด๋์ง ์๋๋ค. (์ซ์๋ง ์
๋ ฅ ๊ฐ๋ฅ)
- ์ทจ์ ๋ฒํผ ํด๋ฆญ โ ์ํ ์์ form์ด ๋ฏธ๋
ธ์ถ๋๋ค.
- ํ ์ธ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ํ ์ธ ์ถ๊ฐ form์ด ๋
ธ์ถ๋๋ค. (๊ธฐ๋ณธ: 10๊ฐ | 10%)
- ํ ์ธ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ํ ์ธ ์ถ๊ฐ form์ด ์ถ๊ฐ๋๋ค.
- ํ ์ธ ์๋ input์ type="number"์ด๋ฉฐ min="1" ์์ฑ์ด ์์ด 0 ์ดํ ์
๋ ฅ ์ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation์ด ์๋ํ๋ค.
- ํ ์ธ์จ input์ type="number"์ด๋ฉฐ max="100" ์์ฑ์ด ์์ด 100 ์ด์ ์
๋ ฅ ์ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation์ด ์๋ํ๋ค.
- ๊ฐ ํ ์ธ ํญ๋ชฉ์ X ๋ฒํผ ํด๋ฆญ โ ํด๋น ํ ์ธ ํญ๋ชฉ์ด ์ญ์ ๋๋ค.
- ํ์๊ฐ(์ํ๋ช
, ๊ฐ๊ฒฉ, ์ฌ๊ณ )์ ์
๋ ฅํ๊ณ ์์ ๋ฒํผ ํด๋ฆญ โ ์ํ์ด ์์ ๋๋ค.
- ์ํ ์์ form์ด ๋ฏธ๋
ธ์ถ๋๋ค.
- ์ํ ์์ ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (3์ด ํ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ค)
- ์ฟ ํฐ ๊ด๋ฆฌ ํญ ํด๋ฆญ โ ์ฟ ํฐ ๊ด๋ฆฌ ์ฝํ
์ธ ๊ฐ ๋
ธ์ถ๋๋ค.
- ์ญ์ ๋ฒํผ ํด๋ฆญ โ ํด๋น ์ฟ ํฐ์ด ์ญ์ ๋๋ค.
- ์ญ์ ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (3์ด ํ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ค)
- ์ญ์ ํ ์ฟ ํฐ์ด ํ์ฌ ์ ํ๋ ์ฟ ํฐ์ด๋ฉด ์๋์ผ๋ก ํด์ ๋๋ค.
- ์ ์ฟ ํฐ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ โ ์ ์ฟ ํฐ ์์ฑ form์ด ๋
ธ์ถ๋๋ค.
- ์ทจ์ ๋ฒํผ ํด๋ฆญ โ ์ ์ฟ ํฐ ์์ฑ form์ด ๋ฏธ๋
ธ์ถ๋๋ค.
- ์ฟ ํฐ๋ช
์ ์
๋ ฅํ์ง ์๊ณ ์ฟ ํฐ ์์ฑ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ์ฟ ํฐ์ฝ๋๋ฅผ ์
๋ ฅํ์ง ์๊ณ ์ฟ ํฐ ์์ฑ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ์ฟ ํฐ ์ฝ๋ ์
๋ ฅ ์ ์๋์ผ๋ก ๋๋ฌธ์๋ก ๋ณํ๋๋ค.
- ํ ์ธ๊ธ์ก์ ์
๋ ฅํ์ง ์๊ณ ์ฟ ํฐ ์์ฑ ๋ฒํผ ํด๋ฆญ โ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ validation ์๋ฌ๊ฐ ๋
ธ์ถ๋๋ค.
- ํ ์ธ ํ์
select ํด๋ฆญ โ ์ ํํ ๊ฐ์ผ๋ก ์ฟ ํฐ ํ ์ธ ํ์
์ด ๋ณ๊ฒฝ๋๋ค.
- ์ด๋ฏธ ์กด์ฌํ๋ ์ฟ ํฐ ์ฝ๋๋ฅผ ์
๋ ฅํ๊ณ ์ฟ ํฐ ์์ฑ ๋ฒํผ ํด๋ฆญ โ ์๋ฌ ํ ์คํธ ํ์
์ด ๋ฌ๋ค.
- ํ์๊ฐ(์ฟ ํฐ๋ช
, ์ฟ ํฐ ์ฝ๋, ํ ์ธ ๊ธ์ก)์ ์
๋ ฅํ๊ณ ์ฟ ํฐ ์์ฑ ๋ฒํผ ํด๋ฆญ โ ์ฟ ํฐ ๋ชฉ๋ก์ ์ถ๊ฐ๋๋ค.
- ์ ์ฟ ํฐ ์์ฑ form์ด ๋ฏธ๋
ธ์ถ๋๋ค.
- ์ฟ ํฐ ์ถ๊ฐ ์ฑ๊ณต ํ ์คํธ ํ์
์ด ๋ฌ๋ค. (3์ด ํ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ค)
- ์ผํ๋ชฐ๋ก ๋์๊ฐ๊ธฐ ๋ฒํผ ํด๋ฆญ โ ์ผํ๋ชฐ ํ์ด์ง๋ก ๋์๊ฐ๋ค.
- ๋ฐ์ดํฐ ์ ์ฅ/๋ณต์
- ์ํ, ์ฟ ํฐ ๋ฐ์ดํฐ๊ฐ localStorage์ ์๋์ผ๋ก ์ ์ฅ๋๋ค.
- ํ์ด์ง ์๋ก๊ณ ์นจ ์ ์ ์ฅ๋ ๋ฐ์ดํฐ๊ฐ ์๋์ผ๋ก ๋ณต์๋๋ค.
(2-2) Action / Calculation / Data๋ก ์ฌ๋ถ๋ฅ ์์์ ํ ์คํธ๋ก ์ ๋ฆฌํ ๋ด์ฉ์ FP ๊ด์ ์์ Action / Calculation / Data๋ก ์ฌ๋ถ๋ฅํ์ต๋๋ค.
1๏ธโฃ Action (๋ถ์ํจ๊ณผ)
[์ผํ๋ชฐ]
- ๊ฒ์ input ์ ๋ ฅ
- ์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ ๋ฒํผ ํด๋ฆญ
- ์๋ input ํด๋ฆญ
- ์ฟ ํฐ select ํด๋ฆญ
- ๊ฒฐ์ ๋ฒํผ ํด๋ฆญ
- ์ฅ๋ฐ๊ตฌ๋ X ๋ฒํผ ํด๋ฆญ
- ๊ด๋ฆฌ์ ํ์ด์ง๋ก ๋ฒํผ ํด๋ฆญ
- ํ ์คํธ ์๋ฆผ ํ์/์ ๊ฑฐ
- localStorage ์๋ ์ ์ฅ
- ๊ฒ์ debounce ์ฒ๋ฆฌ
[๊ด๋ฆฌ์]
- ์ ์ํ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ
- ์ทจ์ ๋ฒํผ ํด๋ฆญ
- ์ํ๋ช ์ ๋ ฅ
- ๊ฐ๊ฒฉ ์ ๋ ฅ
- ์ฌ๊ณ ์ ๋ ฅ
- ํ ์ธ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ
- ํ ์ธ ํญ๋ชฉ X ๋ฒํผ ํด๋ฆญ
- ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ
- ์ญ์ ๋ฒํผ ํด๋ฆญ
- ์์ ๋ฒํผ ํด๋ฆญ
- ์ฟ ํฐ ๊ด๋ฆฌ ํญ ํด๋ฆญ
- ์ญ์ ๋ฒํผ ํด๋ฆญ
- ์ ์ฟ ํฐ ์ถ๊ฐ ๋ฒํผ ํด๋ฆญ
- ์ทจ์ ๋ฒํผ ํด๋ฆญ
- ์ฟ ํฐ๋ช ์ ๋ ฅ
- ์ฟ ํฐ์ฝ๋ ์ ๋ ฅ
- ํ ์ธ๊ธ์ก ์ ๋ ฅ
- ํ ์ธ ํ์ select ํด๋ฆญ
- ์ฟ ํฐ ์์ฑ ๋ฒํผ ํด๋ฆญ
- ์ผํ๋ชฐ๋ก ๋์๊ฐ๊ธฐ ๋ฒํผ ํด๋ฆญ
2๏ธโฃ Calculation (์์ ๋ก์ง)
- ํํฐ๋ง
- ํ ์ธ ๊ณ์ฐ
- ์๋ ๊ณ์ฐ
- validation ํ๋จ
- ์ฟ ํฐ ์ฝ๋ ๋๋ฌธ์ ๋ณํ
- ์ฌ๊ณ ๊ณ์ฐ
- ๊ฐ๊ฒฉ ํฌ๋งทํ
- ์ฅ๋ฐ๊ตฌ๋ ์ด ๊ฐ์ ๊ณ์ฐ
- ์ฟ ํฐ ์ ์ฉ ๊ฐ๋ฅ ์ฌ๋ถ ํ๋จ
- ์ค๋ณต ์ฟ ํฐ ์ฝ๋ ๊ฒ์ฆ
- ์ฃผ๋ฌธ๋ฒํธ ์์ฑ
3๏ธโฃ Data (์ ์ /์ํ ๋ฐ์ดํฐ)
- ์ํ ๋ฆฌ์คํธ
- ์ฅ๋ฐ๊ตฌ๋ ๋ฆฌ์คํธ
- ์ฟ ํฐ ๋ฆฌ์คํธ
- ์ ๊ท ์ฟ ํฐ form ๋ฐ์ดํฐ
- ํ ์ธ ์ ์ฑ
- ์ ๊ท ์ํ form ๋ฐ์ดํฐ
- ์ํ ์์ form ๋ฐ์ดํฐ
- ๊ฒ์์ด (searchTerm, debouncedSearchTerm)
- ์ ํ๋ ์ฟ ํฐ (selectedCoupon)
- ๊ด๋ฆฌ์ ๋ชจ๋ ์ํ (isAdmin)
- ์๋ฆผ ๋ฆฌ์คํธ (notifications)
- ํ์ฑ ํญ (activeTab)
- ํผ ํ์ ์ํ (showProductForm, showCouponForm)
- ์์ ์ค์ธ ์ํ ID (editingProduct)
- ์ฅ๋ฐ๊ตฌ๋ ์ด ๊ฐ์ (totalItemCount)
(2-3) ํผ๊ทธ์ผ์ผ๋ก ์๊ฐํํ๊ธฐ ์ด๋ฐ ๊ฑธ ์ฒ์ ํด๋ณด๋ค๋ณด๋ ์ด๋ฐ์๋ ๊ฐ์ด๋๋ฅผ ์ก๊ณ ์ด๋ค ๊ฑธ ์ด๋๋ก ๋ถ๋ฅํ๊ณ ํ์ดํ๋ ์ด๋๊น์ง ์ฐ๊ฒฐํด์ผ ํ ์ง์ ๋ํ ๊ธฐ์ค์ด ์กํ์ง ์์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ ธ์ต๋๋ค.
๊ทธ๋ฌ๋ Q&A ๋ ํ ์ค๊ฐ ํ์ดํ๋ก ์ฐ๊ฒฐํ๋ ๊ฑด ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ์ด๋ ๊ณง a=>b๋ผ๊ณ ํ ๋ a๋ b๋ฅผ ์๊ณ ์์ง๋ง b๋ a๋ฅผ ๋ชจ๋ฅธ๋ค๋ ๋จ๋ฐฉํฅ ํ๋ฆ์ ์๋ฏธํ๋ค๊ณ ํ์ฌ ์ดํด๊ฐ ๊ฐ์ต๋๋ค.
๊ทธ ์ดํ๋ก ๊ฐ๋ณ ํ๋ก์ฐ๋ ์๊ฐํ๋ฅผ ์์ฑํ ์ ์์์ต๋๋ค.
์งํํ ํผ๊ทธ์ผ ๋งํฌ

(3) ๋ณธ๊ฒฉ์ ์ธ ๊ตฌ์กฐ ๊ฐ์
(3-1) ๊ณ ๋ฏผ
1๏ธโฃ ์์ด์ฝ ์ ์
โ ๋ ๋ค ์ญ์ ํ๋ ์์ด์ฝ์ธ๋ฐ, ์ญํ ์ ์ด๋ป๊ฒ ๊ตฌ๋ถ์ง์ด์ผ ํ ๊น?

X ์์ด์ฝ๊ณผ ์ฐ๋ ๊ธฐํต ๋ชจ์ ๋ ๋ค ๋ฌด์ธ๊ฐ๋ฅผ ์ญ์ ํ ๋ ์ฌ์ฉํ๋ ์์ด์ฝ์ ๋๋ค.
๋ค์ด๋ฐ์ ํ ๋ ์๊ฐ์ ์ธ ๊ฑธ ๊ธฐ์ค์ผ๋ก IconX, IconTrash๋ผ๋ ๋ฑ์ ์ด๋ฆ์ผ๋ก ํ๊ฒ ๋๋ฉด ์ถํ์ ๋ง์ฝ ์์ด์ฝ์ด ๋ณ๊ฒฝ๋์์ ๋ ์ด๋ฆ ์์ ์ด๋ ์์ด์ฝ ์ถ๊ฐ ์์ ์ด ํ์ํ๊ฒ ๋๊ณ ์ด๋ ๊ณง ๋ถํ์ํ ์ถ๊ฐ ์์ ์ ์ด๋ํ๊ฒ ๋ฉ๋๋ค.
๊ทธ๋์ ๋๊ฐ์ ์ญํ ์ ๋ช ํํ๊ฒ ์ ํด๋๊ธฐ๋ก ํ์ต๋๋ค.
- X ์์ด์ฝ: ์ผ๋ฐ์ ์ผ๋ก ํผ์ด๋ ๋ชจ๋ฌ ํํ์์ ๋ซ๊ธฐ/์ง์ฐ๊ธฐ(on/off ๊ฐ๋ฅ)์ ์ญํ ์ ํ๋ ์์ด์ฝ => IconClose
- ์ฐ๋ ๊ธฐํต ์์ด์ฝ: ์๊ตฌ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ๋ ์ญํ ์ ํ๋ ์์ด์ฝ => IconDelete ๊ทธ๋ ๊ฒ ํ๋ ๋ค์ด๋ฐ์ ์ฝ๊ฒ ์งํํ ์ ์์์ต๋๋ค!
โ ๋ ๋ค ์ฅ๋ฐ๊ตฌ๋ ๋ชจ์์ธ๋ฐ, ์ญํ ์ ์ด๋ป๊ฒ ๊ตฌ๋ถ์ง์ด์ผ ํ ๊น?

์ฒซ๋ฒ์งธ์ ์ ์ฌํ ๊ณ ๋ฏผ์ผ๋ก, ๋ ๋ค ์ฅ๋ฐ๊ตฌ๋ ๋ชจ์์ธ๋ฐ ์ด๋ป๊ฒ ๋ค์ด๋ฐํ ์ง ๊ณ ๋ฏผ๋์ต๋๋ค. ๊ทธ๋๋ ์์ ๊ฒฝํ์ ๊ฒช๊ณ ๋๋ ์ด๋ฒ์๋ ์ญํ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ๋ถํด๋ดค์ต๋๋ค.
- ์นดํธ ์์ด์ฝ: ์ฅ๋ฐ๊ตฌ๋ ๊ฐ์๋ฅผ ๋ณด์ฌ์ฃผ๊ฑฐ๋ ํด๋ฆญ ์ ์ก์ ์ด ์กด์ฌํ ๋งํ ์์ญ(ํ์ฌ๋ ํด๋น ๊ธฐ๋ฅ๊น์ง๋ ๋ฏธ๊ฐ๋ฐ ์ํ) => IconCartButton
- ์ผํ๋ฐฑ ์์ด์ฝ: ๋จ์ํ ์ฅ์ ์์ => IconCartSymbol
2๏ธโฃ ๋์ผํ ๋ด์ฉ์ ํ ์คํธ ํ์
์ธ๋ฐ ์ค๋ณต ๋
ธ์ถ์ ํ์ฉํด๋ ๋๋๊ฐ?
๋์ผํ ๋ด์ฉ์ ํ ์คํธ ํ์
์ด ์์ง ํ๋ฉด์์ ์ฌ๋ผ์ง์ง ์์๋๋ฐ ํธ์ถํ๋๋งํผ ๋
ธ์ถ๋๋ ๊ฒ ์๋ฌ์ฒ๋ผ ๋ณด์ธ๋ค๊ณ ์๊ฐํ์ต๋๋ค.
๊ทธ๋์ ๋์ผํ ๋ด์ฉ์ด๋ผ๋ฉด ํด๋น ํ ์คํธ ํ์
์ด ์ฌ๋ผ์ง๊ธฐ ์ ๊น์ง๋ ์ค๋ณต ํธ์ถ์ ๋ง๋ ๊ฒ์ผ๋ก ๊ฐ์ ํ์ต๋๋ค.
3๏ธโฃ ์ํ๋ชฉ๋ก์ด ๋น์ด์์ผ๋ฉด table ๋ถ๋ถ๋ถํฐ ์ ๋์์ผ ํ๋ ๊ฒ ์๋๊ฐ?
๊ธฐ์กด์๋ ์ํ ๋ชฉ๋ก์ด ๋น์ด์์ด๋ table header ๋ถ๋ถ๊น์ง๋ ๋
ธ์ถ๋๊ณ body ๋ถ๋ถ๋ง ๋ฏธ๋
ธ์ถ๋๋๋ก ์์
๋์ด์์์ง๋ง,
๊ฐ์ธ์ ์ผ๋ก ์ด๊ฑด ์ ํฉํ์ง ์์ UI๋ผ๊ณ ํ๋จ๋์ด table ์์ฒด๊ฐ ๋ฏธ๋
ธ์ถ๋๋๋ก ์์ ํ์ต๋๋ค.
4๏ธโฃ isRecommended๋ ์ด๋ป๊ฒ ํ์ธํ๋?
์ํ ๊ตฌ์กฐ์์๋ isRecommended๋ฅผ ๊ธฐ์ค์ผ๋ก BEST ๋ฑ์ง ๋
ธ์ถ ์ฒ๋ฆฌ๋ฅผ ํ๊ณ ์์๋๋ฐ
form์์๋ ๋์ ํ isRecommended๋ฅผ ์ ์ดํ๋ ์์ญ์ ์ฐพ์ ์ ์์๊ณ ์ด์ํ ๋ถ๋ถ์ด๋ผ๊ณ ์๊ฐํ์ต๋๋ค.
์ผ๋ฐ์ ์ผ๋ก BEST ๋ฑ์ง๋ ๊ด๋ฆฌ์ ์ฌ๋์ผ๋ก ๋ ธ์ถ์ํค๊ธฐ ๋๋ฌธ์ form์์ isRecommended๋ฅผ ์ ์ฉํ ์ ์๋๋ก ๊ฐ์ ํ์ต๋๋ค.
5๏ธโฃ ์๋ฏธ์๋ ๋ถ๊ธฐ ๋ถํ์ํ ๋ถ๊ธฐ๋ ์ญ์ ํ์ต๋๋ค!
{(activeTab === "products" ? products : products).map((product) =>
(3-2) ๋์์ธ ํจํด ์ ์ฉ 1๏ธโฃ ์์ฑ ํจํด(Creational Patterns) โFactory Method(ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด) ์ฟ ํฐ ์์ฑ ์ ๋ณต์กํ ๊ฒ์ฆ ๋ก์ง์ ์บก์ํํ์ฌ ์ผ๊ด์ฑ์ ๋ณด์ฅํฉ๋๋ค.
// models/coupon.ts
export interface AddCouponResult {
coupons: Coupon[];
success: boolean;
errorMessage?: string;
}
export const addCoupon = (
coupons: Coupon[],
newCoupon: Coupon
): AddCouponResult => {
// 1. ๊ฒ์ฆ
const validation = validateCouponForm(newCoupon);
if (!validation.isValid) {
return {
coupons,
success: false,
errorMessage: validation.errorMessage,
};
}
// 2. ์ค๋ณต ์ฒดํฌ
if (isCouponCodeDuplicate(coupons, newCoupon.code)) {
return {
coupons,
success: false,
errorMessage: "์ด๋ฏธ ์กด์ฌํ๋ ์ฟ ํฐ ์ฝ๋์
๋๋ค.",
};
}
// 3. ์ฟ ํฐ ์์ฑ ๋ฐ ๋ฐํ
return {
coupons: [...coupons, newCoupon],
success: true,
};
};
// AdminCouponForm.tsx
const result = addCoupon(coupons, couponForm);
if (!result.success) {
handleNotificationAdd(result.errorMessage || "", "error");
return;
}
setCoupons(result.coupons);
2๏ธโฃ ๊ตฌ์กฐ ํจํด(Structural Patterns) โFacade(ํ์ฌ๋ ํจํด)
// models/cart.ts
export const calculateCartTotal = (
cart: CartItem[],
selectedCoupon: Coupon | null
): {
totalBeforeDiscount: number;
totalAfterDiscount: number;
} => {
// ๋ด๋ถ์ ์ผ๋ก ์ฌ๋ฌ ๋ณต์กํ ๊ณ์ฐ์ ์ํ
const totalBeforeDiscount = calculateCartOriginalTotal(cart);
const totalAfterItemDiscount = calculateTotalBeforeCoupon(cart);
const totalAfterDiscount = applyCouponDiscount(
totalAfterItemDiscount,
selectedCoupon
);
return {
totalBeforeDiscount,
totalAfterDiscount,
};
};
๋ณต์กํ ํ ์ธ ๊ณ์ฐ ๋ก์ง์ ๋ถ๋ฆฌํจ์ผ๋ก์จ ์ปดํฌ๋ํธ์์๋ calculateCartTotal(cart, coupon)๋ง ํธ์ถํ๋ฉด ๋ฉ๋๋ค.
// ShoppingCouponPayment.tsx
const totals = calculateCartTotal(cart, selectedCoupon);
โComposite (์ปดํฌ์งํธ ํจํด) ์์ ์์ ํจ์๋ค์ ์กฐํฉํ์ฌ ๋ณต์กํ ๋ก์ง์ ๊ตฌํํจ์ผ๋ก์จ ๊ฐ ํจ์์ ๋ ๋ฆฝ์ ์ธ ํ ์คํธ๊ฐ ๊ฐ๋ฅํ๊ณ ํจ์ ์ฌ์ฌ์ฉ์ฑ์ด ํฅ์๋ฉ๋๋ค.
// calculateItemTotal์ ์ฌ๋ฌ ํจ์๋ฅผ ์กฐํฉ
export const calculateItemTotal = (
cart: CartItem[],
item: CartItem
): number => {
// ํ ์ธ์จ ๊ณ์ฐ
const discountRate = getMaxApplicableDiscount(cart, item);
// ํ ์ธ ๊ฐ๊ฒฉ ๊ณ์ฐ
return calculateDiscountedPrice(
item.product.price,
item.quantity,
discountRate
);
};
// getMaxApplicableDiscount๋ ์ฌ๋ฌ ํจ์ ์กฐํฉ
export const getMaxApplicableDiscount = (
cart: CartItem[],
item: CartItem
): number => {
// ๊ธฐ๋ณธ ํ ์ธ
const baseDiscount = getMaxDiscountRate(
item.product.discounts,
item.quantity
);
// ๋๋ ๊ตฌ๋งค ํ ์ธ
if (hasBulkPurchase(cart)) {
return Math.min(baseDiscount + 0.05, 0.5);
}
return baseDiscount;
};
3๏ธโฃ ํ๋ ํจํด(Behavioral Patterns) โStrategy(์ ๋ต ํจํด) ํ ์ธ ํ์ (amount/percentage)์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ณ์ฐ ๋ฐฉ์์ ์ ์ฉํจ์ผ๋ก์จ ์๋ก์ด ํ ์ธ ํ์ ์ถ๊ฐ ์ ํ์ฅ์ด ์ฉ์ดํฉ๋๋ค.
// models/coupon.ts
export const applyCouponDiscount = (
totalBeforeCoupon: number,
coupon: Coupon | null
): number => {
if (!coupon) {
return totalBeforeCoupon;
}
// Strategy: ํ ์ธ ํ์
์ ๋ฐ๋ผ ๋ค๋ฅธ ์๊ณ ๋ฆฌ์ฆ ์ ์ฉ
if (coupon.discountType === "amount") {
// ์ ์ก ํ ์ธ ์ ๋ต
return Math.max(0, totalBeforeCoupon - coupon.discountValue);
} else {
// ์ ๋ฅ ํ ์ธ ์ ๋ต
return Math.round(
totalBeforeCoupon * (1 - coupon.discountValue / 100)
);
}
};
โTemplate Method(ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด) - ๋ถ๋ถ์ ์ ์ฉ ๊ฐ ๋จ๊ณ๋ฅผ ๋ช ํํ ๋ถ๋ฆฌํจ์ผ๋ก์จ ๊ฒ์ฆ โ ์ฒดํฌ โ ์์ฑ์ ์์๊ฐ ํญ์ ์ ์ง๋๋๋ก ํฉ๋๋ค.
// coupon.ts
export const addCoupon = (
coupons: Coupon[],
newCoupon: Coupon
): AddCouponResult => {
// ํ
ํ๋ฆฟ: 1. ๊ฒ์ฆ โ 2. ์ค๋ณต ์ฒดํฌ โ 3. ์์ฑ
const validation = validateCouponForm(newCoupon); // 1๋จ๊ณ
if (!validation.isValid) {
return { coupons, success: false, errorMessage: validation.errorMessage };
}
if (isCouponCodeDuplicate(coupons, newCoupon.code)) { // 2๋จ๊ณ
return { coupons, success: false, errorMessage: "์ด๋ฏธ ์กด์ฌํ๋ ์ฟ ํฐ ์ฝ๋์
๋๋ค." };
}
return { coupons: [...coupons, newCoupon], success: true }; // 3๋จ๊ณ
};
4๏ธโฃ ์ถ๊ฐ ์ค๊ณ ์์น ๋ฐ ํจํด GoF ํจํด ์ธ์๋ ์ ์ฉ๋ ์ค์ํ ์ค๊ณ ์์น๋ค์ ์ ์ฉํ์ต๋๋ค.
โ Pure Function Pattern(์์ ํจ์ ํจํด) ๋์ผํ ์ ๋ ฅ์ ๋ํด ํญ์ ๋์ผํ ์ถ๋ ฅ์ ๋ณด์ฅํ๊ณ ๋๋ฒ๊น ์ด ์ฉ์ดํ๋ค.
// discount.ts
export const getMaxDiscountRate = (
discounts: Discount[],
quantity: number
): number => {
return discounts.reduce((maxDiscount, discount) => {
return quantity >= discount.quantity && discount.rate > maxDiscount
? discount.rate
: maxDiscount;
}, 0);
};
โ Result Pattern(๊ฒฐ๊ณผ ํจํด) ์์ธ ๋์ Result ํ์ ์ ๋ฐํํ์ฌ ์๋ฌ๋ฅผ ๋ช ์์ ์ผ๋ก ์ฒ๋ฆฌํจ์ผ๋ก์จ ํ์ ์์ ์ฑ์ด ํฅ์๋๊ณ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ๊ฐ์ ํ ์ ์์ต๋๋ค.
// cart.ts
export type AddToCartError = "OUT_OF_STOCK" | "EXCEEDS_STOCK" | null;
export interface AddToCartResult {
cart: CartItem[];
error: AddToCartError;
}
export const addProductToCart = (
cart: CartItem[],
product: ProductWithUI
): AddToCartResult => {
const remainingStock = getRemainingStock(product, cart);
if (remainingStock <= 0) {
return { cart, error: "OUT_OF_STOCK" };
}
// ...
return { cart: nextCart, error: null };
};
โ Immutability Pattern (๋ถ๋ณ์ฑ ํจํด) ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์์ฑํจ์ผ๋ก์จ React์ ๋ถ๋ณ์ฑ ์๊ตฌ์ฌํญ์ ์ถฉ์กฑํฉ๋๋ค.
// cart.ts
export const removeProductFromCart = (
cart: CartItem[],
productId: string
): CartItem[] => {
return cart.filter((item) => item.product.id !== productId); // ์ ๋ฐฐ์ด ๋ฐํ
};
export const updateCartItemQuantity = (
cart: CartItem[],
productId: string,
newQuantity: number
): CartItem[] => {
return cart.map((item) =>
item.product.id === productId
? { ...item, quantity: newQuantity } // ์ ๊ฐ์ฒด ์์ฑ
: item
);
};
โSingle Responsibility Principle(๋จ์ผ ์ฑ ์ ์์น) ์ํฐํฐ๋ณ ๋ชจ๋์ ๋ถ๋ฆฌํจ์ผ๋ก์จ ๋ชจ๋ ๊ฐ ๊ฒฐํฉ๋๋ ๊ฐ์์ํค๊ณ ๋ณ๊ฒฝ ์ํฅ ๋ฒ์๋ฅผ ์ต์ํํฉ๋๋ค.
models/
โโโ cart.ts โ ์ฅ๋ฐ๊ตฌ๋ ๊ด๋ จ ๋ก์ง๋ง
โโโ coupon.ts โ ์ฟ ํฐ ๊ด๋ จ ๋ก์ง๋ง
โโโ discount.ts โ ํ ์ธ ๊ด๋ จ ๋ก์ง๋ง
โโโ product.ts โ ์ํ ๊ด๋ จ ๋ก์ง๋ง
โ Separation of Concerns (๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ) ์ปดํฌ๋ํธ์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ถ๋ฆฌํจ์ผ๋ก์จ ์ฌ์ฌ์ฉ์ฑ์ ํฅ์์ํค๊ณ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ๋๋ก ํฉ๋๋ค.
Before (์ปดํฌ๋ํธ์ ๋น์ฆ๋์ค ๋ก์ง ํฌํจ)
// ShoppingCartItem.tsx (์ด์ )
const calculateItemTotal = (item: CartItem): number => {
const { price } = item.product;
const { quantity } = item;
const discount = getMaxApplicableDiscount(item, cart);
return Math.round(price * quantity * (1 - discount));
};
After (๋น์ฆ๋์ค ๋ก์ง์ ๋ชจ๋ธ๋ก ๋ถ๋ฆฌ)
// models/cart.ts
export const calculateItemTotal = (cart, item) => { /* ... */ };
// ShoppingCartItem.tsx
const itemTotal = calculateItemTotal(cart, item);
(4) Jotai ์ ์ฉ ๊ตฌ์กฐ ๊ฐ์ ์ ์งํํ๋ฉฐ props drilling์ด ๊ฑฐ๋ญ๋ ๋๋ง๋ค ์ปดํฌ๋ํธ ๋ถ๋ฆฌ๋ฅผ ๋ ํด์ผ ํ๋ ์ถ์ด์ง๊ธฐ๊น์ง ํ์ต๋๋ค.
src/basic/
โโโ App.tsx (L0) โ ๏ธ Props ์์ฑ
โ โโโ cart: CartItem[]
โ โโโ products: ProductWithUI[]
โ โโโ setCart: Dispatch<...>
โ โโโ addNotification: (message, type) => void
โ
โโโ pages/
โโโ PageShopping.tsx (L1) โ ๏ธ Props ์ ๋ฌ๋ง (์ฌ์ฉ ์ ํจ)
โโโ cart: CartItem[] โฌ๏ธ
โโโ products: ProductWithUI[] โฌ๏ธ
โโโ setCart: Dispatch<...> โฌ๏ธ
โโโ handleNotificationAdd: (message, type) => void โฌ๏ธ
โ
โโโ shopping/
โโโ ShoppingList.tsx (L2) โ ๏ธ Props ์ ๋ฌ๋ง (์ฌ์ฉ ์ ํจ)
โโโ cart: CartItem[] โฌ๏ธ
โโโ products: ProductWithUI[] โฌ๏ธ
โโโ setCart: Dispatch<...> โฌ๏ธ
โโโ handleNotificationAdd: (message, type) => void โฌ๏ธ
โ
โโโ product/
โโโ ShoppingProductItem.tsx (L3) โ ๏ธ Props ์ ๋ฌ๋ง (์ฌ์ฉ ์ ํจ)
โโโ cart: CartItem[] โฌ๏ธ
โโโ products: ProductWithUI[] โฌ๏ธ
โโโ setCart: Dispatch<...> โฌ๏ธ
โโโ handleNotificationAdd: (message, type) => void โฌ๏ธ
โ
โโโ components/entity/product/
โโโ ProductItem.tsx (L4) โ
์ต์ข
์ฌ์ฉ์ฒ
โโโ cart: CartItem[] โ
์ค์ ์ฌ์ฉ
โโโ products: ProductWithUI[] โ
์ค์ ์ฌ์ฉ
โโโ setCart: Dispatch<...> โ
์ค์ ์ฌ์ฉ
โโโ handleNotificationAdd: (message, type) => void โ
์ค์ ์ฌ์ฉ
ํ์ง๋ง ๊ทธ๊ฒ ๊ณผ์ ์ ๋ชฉํ์ด๋ ์๋๊ณณํ์ง ์๊ณ props drilling์ ์งํํ๊ณ ๋๋์ด ๊ฐ์ ํ ๋์ ๋๋ค!!!!
์ ์ฉํ๋ ๊ณผ์ ์ ๊ทธ๋ฆฌ ์ด๋ ต์ง ์์์ต๋๋ค. useState๋ก ์ ์ํ๋ ๋ด์ฉ๋ค์ ๋ค Jotai๋ฅผ ํ์ฉํ๋๋ก ๋ณ๊ฒฝํ๋ฉด ๋ก์ปฌ ํ์ด์ง์์๋ ๋ฌธ์ ์์ด ๋์ํ์ต๋๋ค.
(4-1) ๋์์จ ํ ์คํธ์ ๋ก์ปฌ์ ์ฐจ์ด ๊ทธ๋ฌ๋ ํ ์คํธ์์๋ "์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ"๋ฒํผ์ ์ฐพ์ง ๋ชปํด์ ํ ์คํธ๊ฐ 12๊ฐ์ ๋ ์คํจํ์ต๋๋ค..(๋์์จ ํ ์คํธ์ ๋ก์ปฌ์ ์ฐจ์ด)
fireEvent.click(screen.getAllByText('์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ')[0]);
์ค๋ ์ท์ ํ์ธํด๋ณด๋ ํ ์คํธ์ ์๋ฆผ์ด ๋ง์ด ์์ฑ๋์ด ํ์ด์ง์ ๋จ์์์๊ณ ๊ทธ๋ก ์ธํด ๋ฒํผ์ ์ฐพ์ง ๋ชปํ๋ ๊ฒ์ฒ๋ผ ๋ณด์์ต๋๋ค.
์ฆ, ๊ฐ ํ ์คํธ์ ์ํ๊ฐ ๊ฒฉ๋ฆฌ๋์ด์ผ ํ๋ ๊ฒ์ด๊ณ ๋งค ํ ์คํธ๋ง๋ค ์์ ๋ถ๋ถ์ App์ ๋ ๋ํ๊ณ ์์ผ๋ฏ๋ก ๊ฐ App์ด ๋ ๋ฆฝ๋ ์ํ๋ฅผ ๊ฐ์ง๋๋ก ํ๋ฉด ๋์ง ์์๊น ์ถ์์ต๋๋ค.
test('์ํ์ ๊ฒ์ํ๊ณ ์ฅ๋ฐ๊ตฌ๋์ ์ถ๊ฐํ ์ ์๋ค', async () => {
render(<App />);
์ด๋ฅผ ์ํด Provider๋ก App์ ๊ฐ์ธ์ App ๋ ๋๋ง ์ ๋งค๋ฒ ์๋ก์ด Provider๊ฐ ์์ฑ๋๋๋ก ํ๊ณ ์ด๋ฅผ ํตํด ์ด์ ํ ์คํธ์ ์ํ๊ฐ ์ํฅ์ ์ฃผ์ง ์๊ฒ๋ ํ ์ ์์ต๋๋ค!
์ด๋ฒ ๊ณผ์ ๋ฅผ ์งํํ๋ฉด์ ๋๋ ์ ์ ๋ ๊ฑฐ์ ์ฝ๋๋ฅผ ๋ถ์ํ๊ณ ๊ฐ์ ํ๋ ์์ ์ ์ฐจ๋ผ๋ฆฌ ๋ช ํํ ๊ธฐ์ค์ด ์์ด์ ์ ๊ทผํ๊ธฐ ์ฌ์ ์ง๋ง, ์ฒ์๋ถํฐ ์ฝ๋๋ฅผ ์์ฑํ ๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ด๋ ๋์์ธ ํจํด์ ์์ฐ์ค๋ฝ๊ฒ ๊ณ ๋ คํ๋ ๊ฒ์ ํจ์ฌ ์ด๋ ต๋ค๋ ๊ฒ์ด์์ต๋๋ค.
์์ผ๋ก๋ ๊ธฐ๋ฅ ๊ตฌํ์ ๋ฐ๋ก ์์ํ๋ ๋์
- ๊ธฐ๋ฅ ํ๋ก์ฐ๋ฅผ ์ค๊ณํ๊ณ
- Action / Calculation / Data ๋ฅผ ์ ๋ฆฌํ๊ณ
- ์ํฐํฐ ๋จ์๋ก ๊ตฌ์กฐ๋ฅผ ๋จผ์ ์ก์ ๋ค
- ๊ทธ ํ์ ์ค์ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ์ ์ผ๋ก ์ฒ์๋ถํฐ ๊ตฌ์กฐ์ ํ๋ฆ์ ์ค๊ณํ๋ ์ต๊ด์ ๋ง๋ค๊ณ ์ถ์ต๋๋ค.
์ด๋ฒ ๊ณผ์ ๋ฅผ ํตํด ๊ทธ ์ค์์ฑ์ ์ฒด๊ฐํ ์ ์์๊ณ , ๋ค์ ํ๋ก์ ํธ๋ ๊ธฐ๋ฅ ๊ฐ๋ฐ์ ์ ์ฉํด๋ณด๊ณ ์ถ์ต๋๋ค!
- ์ฒ์๋ถํฐ ๊ธฐ๋ฅ๊ณผ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ ๋ ์ด๋ค ๊ธฐ์ค์ด๋ ์ ๊ทผ ๋ฐฉ์์ผ๋ก ์์ํ๋ฉด ์ข์๊น์?
- ๊ตฌ์กฐ ์ค๊ณ ๋จ๊ณ์์ ํผ๊ทธ์ผ์ด๋ ๋ ธ์ ์ ์ด๋ค ๋ด์ฉ์ ์ ๋ฆฌํ๋ฉด ์ค์ ์์ ๊ฐ์ฅ ํจ๊ณผ์ ์ธ์ง ๋ ธํ์ฐ๊ฐ ์์๊น์?
- ํจํด๊ณผ ํจ์ํ ์ฌ๊ณ ๋ฅผ ์์ฐ์ค๋ฝ๊ฒ ์ ์ฉํ ์ ์๋๋ก ํ๋ จํ๋ ๋ฐฉ๋ฒ์ด ๊ถ๊ธํฉ๋๋ค!
์์ธํ ๊ตฌํ ๊ณผ์ ๊ณผ ํ๊ณ ๋ ์๋ ๋ธ๋ก๊ทธ์ ์ ๋ฆฌํ์ต๋๋ค! ๐ 7์ฃผ์ฐจ_๋์์ธ ํจํด๊ณผ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ๊ทธ๋ฆฌ๊ณ ์ํ ๊ด๋ฆฌ ์ค๊ณ WIL 7์ฃผ์ฐจ_Chapter3-2. ๋์์ธ ํจํด๊ณผ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ๊ทธ๋ฆฌ๊ณ ์ํ ๊ด๋ฆฌ ์ค๊ณ