๐ก 13. ์ปดํ์ด๋ ์ปดํฌ๋ํธ (Compound Components)
๐ ๊ฐ์
์ ์ด์ ์ญ์ ์ ๊ทนํ์ผ๋ก ๋์ด์ฌ๋ฆฐ ์ค์ ๋ ๊ณ ๋ธ๋ก ์ค๊ณ ํจํด. ์ปดํฌ๋ํธ๋ค์ด ์๋ฌต์ ์ผ๋ก ์ํ๋ฅผ ๊ณต์ ํ๋ฉฐ ํ๋์ ๊ฑฐ๋ํ ์ํ๊ณ๋ฅผ ์ด๋ฃจ๋ ๋ง๋ฒ์ ๋ชฉ๊ฒฉํฉ๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
<Select>ํ๊ทธ์<option>ํ๊ทธ๋ค์ฒ๋ผ, ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ ํ๋๋ก ๋ญ์ณ ์๋ํ๋ ํจํด์ ์๋ฆฌ๋ฅผ ํ์ ํ๋ค.- Props ์ง์ฅ ์์ด๋, ๋ถ๋ชจ ์ปจํ ์ด๋๊ฐ ์์ ์กฐ๊ฐ(๋ธ๋ก)๋ค์๊ฒ ์กฐ์ฉํ ์ํ๋ฅผ ํผํธ๋ ค์ฃผ๋ ๋ง๋ฒ(Context ์ฐ๊ณ)์ ์ค์ค๋ก ๊ตฌํํ ์ ์๋ค.
- ์ฌ๋ด ๋์์ธ ์์คํ (UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ)์ ๋ง๋ค 0ํฐ์ด ํต์ฌ ์ง์(Dot Notation ํ๊ธฐ๋ฒ)์ ์์ ๋ฃ๋๋ค.
๐ ๋ชฉ์ฐจ
- ๐ค ์ ์์์ผ ํ๋๊ฐ:
Props๋ก ์ฑ์ฌ๋ฃ๊ธฐ์ ํ๊ณ์น ๋๋ฌ - ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ ๊ทน์ ์ฒด๋: ์ค์ ์ปดํ์ด๋ ๋ธ๋ก ๊ตฌ์ถํ๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 15๋ถ / ํต์ฌ ํํธ: 8๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ์์(PM):"์ํธ ๋! ์ฐ๋ฆฌ๊ฐ ์ง์ ๋ง๋ ๋๋กญ๋ค์ด(Dropdown) ๊ณตํต ์ปดํฌ๋ํธ ๋ง์ด์์. ์ด๋ค ํ์ด์ง์์ ๋๋ ์ ๋ ์ ๋๋ฉ์ด์ ์ ๋ฃ๊ณ ์ถ๊ณ , ์ด๋ค ๊ณณ์์ ํญ๋ชฉ๋ค์ ์์ด์ฝ์ ๋ฐ๊ณ ์ถ๋์."
- ์ํธ(๋ฆฌ๋):"์์ฒ ๋, ํน์ ๋ ๋๋กญ๋ค์ด์
hasAnimation,iconTypeํ๋กญ์ค ๋ซ๊ณ ๊ณ์ จ์ต๋๊น?" - ์์ฒ (์ ์ ):(ํ ์นซ) "...์ด๋ป๊ฒ ์์ จ์ด์?"
- ์ํธ(๋ฆฌ๋): "๋ค ์ง์ฐ์๊ณ , ์ ๋ฅผ ๋ฐ๋ผ์ค์ธ์. ์ฐ๋ฆฌ๊ฐ ๋ง๋ค ๊ฑด ์์ ํ ํ๋ฒ๊ฑฐ๊ฐ ์๋๋ผ, ๊ทธ์ ๋นต, ํจํฐ, ์น์ฆ๋ผ๋ ์ฌ๋ฃ ํต์ผ ๋ฟ์ ๋๋ค. ์ปดํ์ด๋ ํจํด์ ์๋ ค๋๋ฆฌ์ฃ ."
๐ค ์ ์์์ผ ํ๋๊ฐ: Props๋ก ์ฑ์ฌ๋ฃ๊ธฐ์ ํ๊ณ์น ๋๋ฌ
์ฐ๋ฆฌ๋ ์์ฃผ ๋ณตํฉ์ ์ธ UI ์์๋ค์ ๋ง๋ฉ๋๋ค.
์์ฝ๋์ธ(์ด๋ ธ๋ค ๋ซํ๋ ํจ๋), ํญ(Tab), ๋ก๋ฉ์ด ๋๋ ๋๋กญ๋ค์ด ๋ฉ๋ด, ์ฌ๋ผ์ด๋ ์บ๋ฌ์
๋ฑ์ด ๋ํ์ ์ด์ฃ .
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
๋๋กญ๋ค์ด ์ปดํฌ๋ํธ ํ๋์ ๋ฐฐ์ด ๋ฐ์ดํฐ(options)๋ง ์์ง ํ๋กญ์ค๋ก ๋์ ธ์ ๊ทธ๋ฆด ๋์ ๋์ฐํจ์ ๋๊ปด๋ณธ ์ ์๋๊ฐ?
// โ ์์ฒ ์ด์ ๋์ฐํ JSON ๋
ธ๊ฐ๋ค ์ ์ธํ ๋๋กญ๋ค์ด
const myOptions = [
{ label: "๋ด ์ ๋ณด", value: "info", icon: "๐ค", disabled: false },
{ label: "์ญ์ ํ๊ธฐ", value: "delete", icon: "๐๏ธ", disabled: true, textDanger: true } // ๐จ ์ปค์คํ
์ ํ๊ณ
];
// ์ด ๊ป๋ฐ๊ธฐ ํ๋๋ก ๋ด๋ถ์ ๋ฏธ์ธํ ์์, ์์ด์ฝ ์กฐ์ ์ด ๊ฐ๋ฅํ ๊น?
<SuperDropdown
options={myOptions}
onChange={handleChange}
closeOnSelect={true}
animation={{ speed: 300, type: 'fade' }} // ์ ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๊ฐ ๊ธฐ๊ดดํด์ง๋ค!
/>์ ์ฝ๋๋ 12๊ฐ์์ ๋งํ๋ ๊ฐ๋ฐฉ-ํ์ ์์น ํ๊ดด์ ์ ํ์
๋๋ค. ์ด ๋ฐ์ดํฐ ๋ฐฐ์ด๋ง์ผ๋ก๋ "์ญ์ ํ๊ธฐ"๋ผ๋ ํ
์คํธ ํ ์ค๋ง ๋นจ๊ฐ์์ผ๋ก ๊ทธ๋ฆฐ๋ค๊ฑฐ๋, ์ค๊ฐ์ --- ๊ตฌ๋ถ์ (Divider)์ ๋ฑ ํ๋ ๋ฃ๊ณ ์ถ๋ค๋ ์์ํ ์ปค์คํ
UI ์๊ตฌ๋ฅผ ๋์ ํ ์์๊ฒ ์์ฉํ ์๊ฐ ์์ต๋๋ค.
์ด๊ฑธ ์๋ฒฝํ๊ฒ ํด๊ฒฐํด์ฃผ๋ ์๋ฆ๋ค์ด HTML ๋ด์ฅ ํ๊ทธ๋ค์ ์ฐ๋ฆฌ๋ ์ด๋ฏธ ๊ฒฝํํด๋ดค์ต๋๋ค. ๋ฐ๋ก ์ด๊ฒ์ ๋๋ค:
<select>
<option>์ง์ฅ๋ฉด</option>
<option selected>์งฌ๋ฝ</option>
</select>๋ถ๋ชจ(<select>)์ ์์(<option>)์ด ํ๊ทธ๋ก ๋ถ๋ฆฌ๋์ด ์์ผ๋ฉด์๋, ๋ง์น ํ ๋ชธ์ฒ๋ผ ๋๋ํ๊ฒ ๋ถ์ด์ ํ๋์ ๊ธฐ๋ฅ(์ ํํ๊ธฐ)์ ์ฒ๋ฆฌํฉ๋๋ค. ์ด ํํ๋ฅผ ๋ฆฌ์กํธ๋ก ๊ทธ๋๋ก ๊ตฌํํ๋ ๊ฒ์ด ๋ฐ๋ก **์ปดํ์ด๋ ์ปดํฌ๋ํธ (Compound Components)**์
๋๋ค.
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
์์ฒ ์ด์ ๋ฉ๋ด์ผ์ ์์ ํ ์ฅ๋๊ฐ:
๊ณต์ฅ์์ ๋ก๋ด ์ฅ๋๊ฐ์ ํต์งธ๋ก ๊ตณํ์ ๋ง๋ค์ด ์ด.
"์ด ๋ก๋ด ๋จธ๋ฆฌ์ ๋ฆฌ๋ณธ ๋ฌ์์ค"๋ผ๊ณ ํ๋ฉด ๋ก๋ด ๊ณต์ฅ ์์ฒด๋ฅผ ๋ฐ์ด ๋ด๊ณ ๋๋ฉด(Props ํ๋ผ๋ฏธํฐ)์ ๊ฐ์กฐํด์ผ ํจ.์ปดํ์ด๋ ํจํด (๋ ๊ณ ๋ธ๋ก ์กฐ๋ฆฝ ์ธํธ):
๋ ๊ณ ๋ชธํต(Dropdown)๋ ๊ณ ์ค์์น(Toggle)๋ ๊ณ ํ(Item)
์ 3๊ฐ๋ฅผ ๋ฐ์ค์ ๋ด์ ์ถ์ํจ.
์ฌ์ฉ์๋ ์ด ๋ธ๋ก ์ธํธ๋ค์ ๊ฐ์ ธ์์ ์๊ธฐ ๋ง์๋๋ก ์์๋ฅผ ๋ฐ๊พธ๊ฑฐ๋, ํ ์ฌ์ด์ ์คํฐ์ปค(์ปค์คํ UI)๋ฅผ ๋ง๋๋ก ๋ผ์ ๋ฃ๋ ์กฐ๋ฆฝ ๊ณผ์ ์ ๊ฐ์ง! ํ์ง๋ง ์๋ค ์ ์ ์ด์จ๋ ํ ๊ฐ์กฑ ๋ธ๋ก์ด๋ผ์, ํ์ ๋๋ฅด๋ฉด ์ค์์น๊ฐ ๋๋ฑํ๋ฉฐ ๋ฐ์ํ๋๋ก ํ์ค(Context API)์ด ๋ด๋ถ์ ์ผ๋ก ๋ณด์ด์ง ์๊ฒ ํตํ๊ณ ์์ด.
๐งฉ ๊ทน์ ์ฒด๋: ์ค์ ์ปดํ์ด๋ ๋ธ๋ก ๊ตฌ์ถํ๊ธฐ
์ฐ๋ฆฌ์ ๋ชฉํ๋ ๋ค์๊ณผ ๊ฐ์ด ์๋ฆ๋ต๊ฒ ์์ฑ๋๋(Dot Notation ์ฌ์ฉ) ๋๋กญ๋ค์ด์ ๋ง๋๋ ๊ฒ์ ๋๋ค.
// ๐ฏ ์ต์ข
์ปดํ์ด๋ ๋ฌ์ฑ ๋ชฉํ (์ฌ์ฉํ๋ ์ชฝ ์ฝ๋)
<Dropdown>
<Dropdown.Toggle>๋ฉ๋ด ์ด๊ธฐ</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={goProfile}>๋ด ์ ๋ณด</Dropdown.Item>
<Divider /> {/* ์! ๊ตฌ๋ถ์ ์ ๋ด ๋ง์๋๋ก ๋ ์ ์๋ค! */}
<Dropdown.Item onClick={logout}>
<span className="text-red">๋นจ๊ฐ ๋ก๊ทธ์์</span> {/* ์์ ์ปค์คํ
์์ ! */}
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>โ 1. ํ์ค ๋ง๋ค๊ธฐ (๋ณด์ด์ง ์๋ ๊ณต์ State)
์ด ๋ธ๋ก๋ค์ ์๋ก ๋จ์ด์ ธ ์ ์ธ๋์ง๋ง "๋๋กญ๋ค์ด ๋ฌธ์ด ์ด๋ ธ๋๊ฐ(isOpen)?" ์ํ๋ฅผ ์์์ผ ํฉ๋๋ค. ์ด ํต๋ก๋ฅผ ์ํด 11๊ฐ ๋ฐฉ์ฌ๋ฅ ๊ฒฉ๋ฆฌ๋ฒ์์ ์ผ๋ Context API๋ฅผ ๊บผ๋ด ๋ญ๋๋ค. ์ฌ๊ธฐ์ ๋ถ๋ชจ ๋ฐ๋ก ์๋ ๊ณ์ธต๋ค๋ง ์ฐ๋๊น ๋ฐฉ์ฌ๋ฅ ๊ฑฑ์ ์ ํฌ๊ฒ ์ ํด๋ ๋ฉ๋๋ค!
import { createContext, useContext, useState } from 'react';
// 1๏ธโฃ ์ด ๋ธ๋ก๋ค๋ผ๋ฆฌ๋ง ๋ชฐ๋ ์ํตํ ๋น๋ฐ ํ
๋ ํ์(Context) ์์ฑ
const DropdownContext = createContext();
function useDropdownContext() {
const context = useContext(DropdownContext);
if (!context) throw new Error("Dropdown ํ๋ธ๋ก๋ค์ Dropdown ๋ถ๋ชจ ์์์๋ง ์จ์ผ ํด!");
return context;
}โ 2. ๋ง๋์ญ(์ด๋ฏธ) ์ปดํฌ๋ํธ ์ ์ธ
์ํ๋ฅผ ๋ณด๊ดํ๊ณ , ํ ๋ ํ์ ๊ณต๊ฐ์ ๊น์์ค ๋ถ๋ชจ ๊ป๋ฐ๊ธฐ์ ๋๋ค.
// 2๏ธโฃ ๋๊ฐ๋ฆฌ(Wrapper) ์ปดํฌ๋ํธ ์ ์
export function Dropdown({ children }) {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(prev => !prev);
// ํ
๋ ํ์ ๋ฐฉํ๊ณ , ํ์ ๋ ๊ณ ๋ธ๋ก๋ค(children)์ ๊ทธ๋ฅ ์์ํ๊ฒ ๋๋๋ง!
return (
<DropdownContext.Provider value={{ isOpen, toggle }}>
<div className="dropdown-wrapper relative">{children}</div>
</DropdownContext.Provider>
);
}โ 3. ํ์ ๋ถํ(์์ ํ์ธ )๋ค ๋น์ด๋ด๊ธฐ
์ด์ ์กฐ๊ฐ๋ค์ ๋ง๋ญ๋๋ค. ์ด ์กฐ๊ฐ๋ค์ ๋ฐ์์ ๋ง๊ตฌ์ก์ด๋ก ๋ฐฐ์ด๋๋ ๋ญํ๋ , ์ด๋ป๊ฒ๋ ํ ๋ ํ์ ์ฃผํ์๋ก ์ด๋ฏธ์ ์ํ๋ง ๋ฝ์ ๋จน์ผ๋ฉด ๋ฉ๋๋ค.
// 3๏ธโฃ ๋ถํ 1: ์ค์์น (๋๋ฅด๋ฉด ์์์ ์ง toggle ํจ์ ๋ฐ๋)
function Toggle({ children }) {
const { toggle } = useDropdownContext(); // ํ
๋ ํ์ ๋ฝ๊ธฐ
return <button className="toggle-btn" onClick={toggle}>{children}</button>;
}
// 4๏ธโฃ ๋ถํ 2: ํ์
๋ฉ๋ด (๋ฌธ์ด ๋ซํ์์ผ๋ฉด ์๊ธฐ ์์ ํ๊ดด)
function Menu({ children }) {
const { isOpen } = useDropdownContext(); // ํ
๋ ํ์ ๋ฝ๊ธฐ
if (!isOpen) return null; // ๋ซํ์๋ค? ์ ๊ทธ๋ ค!
return <div className="dropdown-menu absolute box-shadow">{children}</div>;
}
// 5๏ธโฃ ๋ถํ 3: ๊ฐ๋ณ ๋ฒํผ (๋๋ฅด๋ฉด ๊ธฐ๋ฅ ์คํ ํ ๋๋กญ๋ค์ด ๋ฌธ ๋ซ๊ธฐ)
function Item({ children, onClick }) {
const { toggle } = useDropdownContext();
const handleClick = (e) => {
onClick?.(e); // ํ ์ผ ํ๊ณ
toggle(); // ์ด ๋
์์ด ๋๋ฌ๋ ๋ฌธ์ ๋ซ๋๋ก ์ก์
ํธ์ถ!
};
return <div className="dropdown-item" onClick={handleClick}>{children}</div>;
}โ 4. ์ ํ๊ธฐ๋ฒ(Dot Notation) ์ฐ๊ฒฐ ํฉ์ฒด
๋ง์ง๋ง ๊ฐ์ง(๋ฝ๋) ํ์์ ๋๋ค. ์ด ์ปดํฌ๋ํธ ๋ธ๋ก๋ค์ด ํ๋์ ๊ฐ์กฑ์ด๋ผ๋ ๊ฒ์ ๋ช ์ํ๊ธฐ ์ํด, ๋ค์ด๋ฐ์ ๋ฌถ์ด์ค๋๋ค.
// Javascript์์ ํจ์๋ ๊ฐ์ฒด(Object)๋ค! ๊ณ ๋ก ์์ฑ์ ์ถ๊ฐํ ์ ์๋ค.
Dropdown.Toggle = Toggle;
Dropdown.Menu = Menu;
Dropdown.Item = Item;
export default Dropdown;
// ๋! ์ด์ Radix UI, Headless UI์์๋ ๋ณด๋ ๋๊ธฐ์
๊ธ ์ปดํฌ๋ํธ๊ฐ ๋ด ์ฑ์ ๋ค์ด์๋ค!๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
| ์ปดํ์ด๋ ํจํด์ ํต์ฌ ์์ | ์ญํ ๋ฐ ์ค๋ช |
|---|---|
๋ถ๋ชจ ์ปจํ
์ด๋ (Wrapper) | ๊ณตํต์ ์ํ(State)๋ฅผ ์ฅ๊ณ , ์์๋ค์๊ฒ ๋ฟ๋ ค์ค Context.Provider ์ฐ์ฐ์ ์์์ฃผ๋ ์ต์๋จ ์ปดํฌ๋ํธ. |
๋น๋ฐ ํต๋ก (Context API) | ์ปดํ์ด๋์ ์ฌ์ฅ. ์์ ํ์ธ ๋ค์ด ํ
์คํธ๋ก ๋๋ฌ์ธ์ด๋ ๋ช ๋์ค๋ฅผ ํต๊ณผํ๋ , ์ด๋ฏธ๊ฐ ์ง๋ isOpen ๊ฐ์ ์ํ ์กฐ์๊ถ์ ๋ง๊ป ๋๋ฆฌ๊ฒ ํจ. |
๊ฐ๋ณ ์์ ๋ธ๋ก๋ค (Children) | UI์ ์ด๋ป๊ฒ ๋ฐํ๋ , ์์๊ฐ ๋ฐ๋๋ ๊ฐ์์ ๊ธฐ๋ฅ์๋ง ์ถฉ์คํ๊ฒ ๋์ํ๋ ์์ ์กฐ๊ฐ๋ค. IoC ์์ ๋ฌ์ฑ! |
| ์ ํ๊ธฐ (Dot Notation) | Dropdown.Item ์ฒ๋ผ ํ๋์ ๋ค์์คํ์ด์ค๋ก ๋ฌถ์ด ์๋์์ฑ(Intellisense)๊ณผ ๊ฐ๋
์ฑ์ ๋์ด๋ ํ์ด๊ธฐ. |
๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
"๋ณต์กํ ์ฌ์ฌ์ฉ UI(๋ชจ๋ฌ, ํญ, ๋๋กญ๋ค์ด)๋ฅผ ๋ง๋ค๋ ค๊ฑฐ๋ Props์ ํ์ค์ค๋ฌ์ด JSON ๋ฐฐ์ด์ ์ค์ ๋ฃ์ง ๋ง๊ณ , ์กฐ๊ฐ ์กฐ๊ฐ๋ ๋ ๊ณ ๋ธ๋ก ์ปดํ์ด๋๋ก ์ฐข์ด ๋ฐ๊ฒจ๋ผ."
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
Json ๋ฐฐ์ด ์์ง๋ก ๋์ง๋ ๋ฐฉ์๋ง ์ฃผ์ผ์ฅ์ฒ ํ ์๋๋ฐ... Radix UI๋ Headless UI์์ ๋ณด๋ ๊ทธ ๊ฐ์ง ๋๋ <Dropdown.Item> ์ ํ๊ธฐ๋ฒ์ด ์ด๋ ๊ฒ ๋ง๋ค์ด์ง๋ ๊ฑฐ์๋ค๋.
๐ก "๋ถ๋ชจ๋ ํ ๋ ํ์(Context API)๋ฅผ ์จ๊ธฐ๊ณ , ์์๋ค์ ์กฐ๋ฆฝ๋๋ ์์น ์๊ด์์ด ์กฐ์ฉํ ๊ทธ ํ์ ๋นจ์๋จน๋ ๋ ๊ณ ๋ธ๋ก ์ํ๊ณ. ์ด๊ฒ์ด ์ปดํ์ด๋ ์ปดํฌ๋ํธ๋ค!"
์ปดํฌ๋ํธ ์์ ๋จ์ HTML์ ์๋ฌด๋ฆฌ ๊ตฌ๊ฒจ ๋ฃ์ด๋ ํ ๋ ํ์๋ ๋ซ๊ณ ๋ค์ด๊ฐ๋ค๋ ๋ง์ด ์ ๋ง ์์ํ๋ค. ๋น์ฅ ์ฌ๋ด ๋์์ธ ์์คํ ์์ ๋ ๋ด๊ฐ '์ด๊ฑด ์ปดํ์ด๋๋ก ๊ฐ์ผ ํฉ๋๋ค'๋ผ๊ณ ์ดํํด ๋ด์ผ๊ฒ ๋ค. ์ด ์ง๋ฆฟํ ์๋ง์ ์๊ธฐ ์ ์ ์ง์ ๊ฐ์ ํญ ์ปดํฌ๋ํธ ํ๋ ์คํฌ๋์น๋ก ์ง์ ์ง๋ด์ผ๊ฒ ๋ค.
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ๋น์ ์ ์์ฒ ์ด์ ๋๋ฌ์ด JSON Array ๋๋กญ๋ค์ด์ ์ปดํ์ด๋ ์ปดํฌ๋ํธ ํจํด์ผ๋ก ๋ฆฌํฉํ ๋งํ์ต๋๋ค. ์ด๋ ๋ฐ์ํ๋ ์ค๊ณ์(์ํคํ
์ฒ)์ ๊ฐ์ฅ ๊ฑฐ๋ํ๊ณ ์๋ฆ๋ค์ด ์ฅ์ ํ ๊ฐ์ง๋ฅผ ๊ณ ๋ฅด์ธ์.
- A) ์ปดํฌ๋ํธ๊ฐ ํ ํ์ผ ๋ด์ ํ ์ค๋ก ์ค์ด๋ค๋ฉด์ ๋ฒ๋ค๋ง ์ต์ ํ ์๋๊ฐ 300% ํฅ์๋๋ค.
- B) ๋๋กญ๋ค์ด ๋ด๋ถ์ ํน์
<Item />ํ๊ทธ ์ฌ์ด์<div>--- ์ ์ทจ์ ---</div>๊ฐ์ ์์ ํ ์ด์ง์ ์ธ UI๋ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ๊ทธ๋ฅ ์์ง๋ก ๋ฐ์ด ๋ฃ์ด๋ ๊ธฐ์กด ์์คํ (๋ฌธ ๋ซํ๊ณ ์ด๋ฆผ ์ํ ๊ด๋ฆฌ)์ด 1๋ ๊นจ์ง์ง ์๋ ์๋ฒฝํ ํ์ฅ์ฑ(๊ฐ๋ฐฉ ๋ ๋๋ง). - C) Context API๋ฅผ ์ฐ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ๋ธ๋ผ์ฐ์ ์ LocalStorage์ ์๊ตฌ ์ ์ฅ๋๋ ๋ง๋ฒ ๊ฐ์ ๋๊ธฐํ ๊ฒฝํ.
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค: ์ ์ด ์ญ์ ์ฐข๊ธฐ(IoC)์ ๊ถ๊ทน๊ธฐ์ธ ์ค๋ช
์
๋๋ค. ํ๋กญ์ค๋ก options=[{}]์์ผ๋ก ๋์ง ๋๋ ๊ทธ ๋ฐฐ์ด์ ๋ง๊ฒ ๋ด๋ถ์์ for๋ฌธ๊ณผ ๋งํฌ์
์ด ๊ตณ์ด์ ธ(ํ๋์ฝ๋ฉ) ์์ด์ ์ปค์คํ
UI๋ฅผ ๋ฃ๊ธฐ๊ฐ ๋ชจ๋์๊ณ ๊ตฌ๋ฉ ํต๊ณผํ๊ธฐ๋งํผ ๋๋ฌ์ ์ฃ . ๋ฐ๋ฉด <Menu> ์์ <Item/> ๋ ๊ณ ๋ฅผ ์กฐ๋ฆฝํ๋ค๊ฐ ์ค๊ฐ์ ๋นจ๊ฐ ์ค CSS๋ฅผ ๋ฐ๋ , ๊ฑฐ๋ํ ๋ด ์ ๋ณด ๋ฐ์ค UI๋ฅผ ์์ฌ ๋ฐ๋ ๋ฆฌ์กํธ๋ ๊ทธ๋ฅ ๊ฐ๋ณ๊ฒ ๋ ๋๋งํด ์ค๋๋ค. ๊ป๋ฐ๊ธฐ๋ง ์ค ๋ฟ ๋ด๋ถ ์ฑ์ฐ๊ธฐ๋ ์ฌ์ฉ์ ๋ง์ธ ์๋ฒฝํ ํ์ฅ์ฑ์ ๊ฐ์ง๋๋ค.
Q2. ์ปดํ์ด๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ๋, ์ ๊ตณ์ด ๋ถ๋ชจ(Dropdown)๊ฐ ์ํ(isOpen)์ toggle ํจ์๋ฅผ ์์๋ค(Toggle, Item)์๊ฒ props๊ฐ ์๋ Context API ํ
๋ ํ์๋ก ๋ฟ๋ ค๋๋ฉฐ ์ง๊ทธ๋ฝ๊ฒ ์ฐํํ๋ ์๊ณ ๋ฅผ ํ ๊น์?
// ๋ถ๋ชจ
<Dropdown>
{/* props๊ฐ ์๋๋ผ Context๋ก ์์์ ์์์ ์์์ผ์ง๋ผ๋ ๊ดํตํด์ ์ด์ค๋ค! */}
<div className="layout-box">
<Dropdown.Toggle>์ด๊ธฐ</Dropdown.Toggle>
</div>
</Dropdown>- A) ํด๋์ค ๊ธฐ๋ฐ React ์๋ช
์ฃผ๊ธฐ API๊ฐ ๋ ์ด์
props๋ฅผ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์. - B)
children์ฌ์ด์ฌ์ด์ ์ ์ ๊ฐ ์๊ธฐ ๋ง๋๋ก ๊น์<div>ํ๊ทธ๋ค์ด๋ ๋ํผ ๊ป๋ฐ๊ธฐ ๋ ์ด์์์ ๊ฒน๊ฒน์ด ๋ผ์ ๋ฃ์ ์ ์๋๋ฐ, ์ง์ props๋ก ๋ด๋ฆฌ๋ฉด ์ด ๋ผ์ด๋ ์ฅ์ ๋ฌผ ๋๋ฌธ์ Props Drilling์ด ๊ฝ ๋งํ๋ฒ๋ฆฌ๊ธฐ ๋๋ฌธ. - C) ํ์
์คํฌ๋ฆฝํธ(TypeScript)์์ children์ prop์ ๊ฐ์ ๋ก ์ค์
๋ฃ์ผ๋ฉด ์ฆ์ ๋ฐํ์ ์๋ฌ
any type never๋ฅผ ๋ฟ์ด๋ด๊ธฐ ๋๋ฌธ.
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค: ๋ง์ฝ Context๋ฅผ ์ ์ด๋ค๋ฉด ์๋ (๊ณผ๋๊ธฐ) ๋ฐฉ์์ธ React.Children.map ๊ณผ cloneElement๋ผ๋ ์
๋ช
๋์ ๊ตฌ์ ํจ์๋ฅผ ์ด์ฉํด ์ต์ง๋ก ๋ถ๋ชจ ํ๋กญ์ค๋ฅผ ๋ผ์ ๋ฃ์ด์ผ ํ์ต๋๋ค. ํ์ง๋ง ์ด ์ ๋ฐฉ์์ ์ค๊ฐ์ ๊ป๋ฐ๊ธฐ ๋ ์ด์์ ๋ํ <div>๊ฐ ๋ผ์ด๋ค๋ฉด ๊ตฌ๋ฉ์ด ๋์ด์ ธ ์๋์ ์ ํ๋ ์น๋ช
์ ๋ฒ๊ทธ๊ฐ ํฐ์ง๋๋ค! ๋ฐ๋ฉด Context๋ ์๋ฌด๋ฆฌ ๊ป๋ฐ๊ธฐ DOM ๋
ธ๋ ์งํ๋์ ์ผ๋ก ๊น์ด ์ ์ ๊ฐ ์กฐ๋ฆฝํด ๋ค์ด๊ฐ๋๋ผ๋ useContext๋ง ๋ฝ์ ์ฐ๋ฉด ํ
๋ ํ์๋ฅผ ์ฆ์ ๊ดํต ์์ ํ๋ฏ๋ก ์๋ฒฝํ ์ค๊ณ ์ ์ฐ์ฑ์ ํ๋ณดํ ์ ์์ต๋๋ค.
Q3. ์ปดํ์ด๋ ์ปดํฌ๋ํธ์ ๋ํ์ ๋ง๊ฐ์น ๊ธฐ์ ์ธ "์ ํ๊ธฐ๋ฒ(Dot Notation)"์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋จ์ํ ๋ฉ(๊ฐ์ง) ๋ชฉ์ ์ ๋์ด, ๊ฐ๋ฐ ๊ฒฝํ(DX)๊ณผ ํ์ ์๋ค์๊ฒ ๋จ๊ธฐ๋ ๊ฐ๋ ฅํ ์ด์ ์ ๋ฌด์์ธ์ง ์ฃผ๊ด์์ผ๋ก ์์ ํ์ธ์.
import { Dropdown } from './Dropdown';
<Dropdown.Menu>...</Dropdown.Menu>โ ์ ๋ต ๋ฐ ์ฃผ๊ด์ ํด์ค:
"์ ํ๊ธฐ๋ฒ(Dot Notation)์ ์ปดํฌ๋ํธ๋ค์ ์์๊ฐ๊ณผ ๋ค์์คํ์ด์ค๋ฅผ ๋ช
ํํ๊ฒ ๋จ์ํด ์ฃผ๋ ๊ฐ๋๋ ์ผ์
๋๋ค.
์ฒซ์งธ, ํ์
๊ฐ๋ฐ์๊ฐ Dropdown ์ปดํฌ๋ํธ๋ฅผ ์น๊ณ .์ ๋๋ฅด๋ ์๊ฐ IDE ์๋์์ฑ(Intellisense)์ ์ด ์ปดํฌ๋ํธ๊ฐ ํ์ ์ ์๋ ๋ ๊ณ ๋ถํ ๋ชฉ๋ก(Toggle, Item, Menu)์ด ์ซ ๋จ๋ฉด์ ๋ฌธ์๋ฅผ ๋ณผ ํ์์กฐ์ฐจ ์์ด ์ด๋ป๊ฒ ์กฐ๋ฆฝํด์ผ ํ๋์ง ๋ช
์พํ ๋จ์๋ฅผ ์ค๋๋ค.
๋์งธ, ์๋ง ๊ฐ์ ์์
ํ์ผ์ด ๊ตด๋ฌ๋ค๋๋ ๊ฑฐ๋ ํด๋์์ ๊ณ ์ ์ฐ๊บผ๊ธฐ ๋ ๊ณ ์กฐ๊ฐ๋ค์ธ Item, Menu๋ผ๋, ๋ค๋ฅธ ์ฑ์์๋ ํํ๊ฒ ์ธ ๋ฒํ ๋๋ฌด ํ๋ฒํ ์ด๋ฆ๋ค์ด ์ ์ญ ํด๋ ๊ณต๊ฐ๊ณผ Import ์คํ์ด์ค๋ฅผ ์ด๋ฆ ์ถฉ๋๋ก ์์ด๋ด๋ ๊ฒ์ ๋ฐฉ์ง(ํจํค์ง ์บก์ํ)ํ ์ ์์ต๋๋ค."