๐ฉ๐ป๐จ ๋ณดํต์ ๋๋กญ๋ค์ด ๋ง๋ค๊ธฐ
๋ณดํต ๋๋กญ๋ค์ด์ ๋ง๋ ๋ค๊ณ ํ๋ฉด ์ด๋ป๊ฒ ๋ง๋ค๊น์?
{dropdownClick === scheduleId && isDropdownOpen && (
<Dropdown className={dropdownContainer}>
<Dropdown.Item
text="์์ ํ๊ธฐ"
onClick={handleEditClick}
rightAddon={<Icon name="pencil" size={16} />}
></Dropdown.Item>
<div className={dropdownDivider}></div>
<Dropdown.Item
text="์ญ์ ํ๊ธฐ"
onClick={handleDeleteClick}
rightAddon={<Icon name="delete" size={16} />}
></Dropdown.Item>
</Dropdown>
)}
์๋ง ์ด๋ฐ์์ผ๋ก dropdownClick๋์๋๋ง ๋๋กญ๋ค์ด์ด ์ด๋ฆฌ๋๋ก ๊ตฌํ์ ํ์๊ฒ๋๋ค.
ํ์ง๋ง ์ด๋ฐ ์ฝ๋๋ ์ค๋ณต๋๋ ์ฝ๋๋ฅผ ๋๋ฆด๋ฟ๋๋ฌ ๊ฐ๋ ์ฑ ์ธก๋ฉด์์๋ ์ข์ง ๋ชปํฉ๋๋ค.
๋๋กญ๋ค์ด์ ๋ง๋ค๋ ๋ง๋ค ๋งค๋ฒ ํด๋ฆญํ๋์ง ์ํ๋ฅผ ๋ง๋ค์ด์ค์ผ ํ๋ค๋ณด๋ ๊ฐ๋ฉ์ด๋ ์ํ๊ด๋ฆฌํ ๊ฒ ๋ง์ UI๋จ์ด ๋ ๋ณต์กํด์ง๊ฒ ์ฃ .
๋๋กญ๋ค์ด ๊ฐ์ ์ปดํฌ๋ํธ์ ๊ฒฝ์ฐ ๋์์ธ ์์คํ ์ผ๋ก ๋ฐ๋ก ๋ง๋๋๋ฐ ์ฐจ๋ผ๋ฆฌ ๋์์ธ ์์คํ ํํ ์ํ๊ด๋ฆฌ๋ฅผ ์์ํ๋ฉด ์ด๋จ๊น?! ๋ผ๋ ์๊ฐ์ด ๋ค๊ฒ๋๋ค.
๊ทธ๋์ ๋ํ๋ ํค๋๋ฆฌ์ค ์ปดํฌ๋ํธ ํจํด!
(๋ฒ์ญ) ํค๋๋ฆฌ์ค ์ปดํฌ๋ํธ: ๋ฆฌ์กํธ UI๋ฅผ ํฉ์ฑํ๊ธฐ ์ํ ํจํด
์ ์๋ฅผ ์ดํด๋ณด๋ฉด “ํค๋๋ฆฌ์ค ์ปดํฌ๋ํธ ํจํด์ ๊ณ์ฐ๊ณผ UI ํํ์ ๋ถ๋ฆฌํ์ฌ, ๊ฐ๋ฐ์๊ฐ ๋ค์ฌ๋ค๋ฅํ๊ณ ์ ์ง ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ฉฐ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ถํ ์ ์๋๋ก ์ง์ํฉ๋๋ค.” ๋ผ๊ณ ํ๋ค์.
๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด ์ฌ์ฉ์ฒ์์ ๋๋กญ๋ค์ด์ ์ธ ๋ ๋ฐ๋ก useState๋ก ๋๋กญ๋ค์ด์ ์ด์๋์ง ์ํ๊ด๋ฆฌ๋ฅผ ํด์ฃผ์ง ์๊ณ
<Dropdown>
<Dropdown.Trigger>
<Icon name="more" size={32} />
</Dropdown.Trigger>
<Dropdown.Content className={deleteDropdownContainer}>
<Dropdown.Item
text="์ญ์ ํ๊ธฐ"
onClick={handleDeleteClick}
rightAddon={<Icon name="delete" size={16} />}
></Dropdown.Item>
</Dropdown.Content>
</Dropdown>
์๋ ๊ฒ ๋๋กญ๋ค์ด๋ง ๊ฐ์ ธ๋ค ์ฐ๋ฉด๋๊ฒ ๋ง๋ค์ด๋ณผ๊ฒ๋๋ค! ์ด๋ ๊ฒ ๊ตฌํํ๋ฉด ๊ฐ๋ฐ์๋ ๋น์ฆ๋์ค๋ก์ง๊ณผ UI์ ์ข๋ ์ง์คํ ์ ์๊ฒ ๋ฉ๋๋ค.
๐ฉ๐ป๐จ ํค๋๋ฆฌ์ค ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด๋ณด์!
์ง์ ๊ตฌํํด๋ณด๋ฉด์ ํค๋๋ฆฌ์ค ์ปดํฌ๋ํธ์ ๊ผญ ํ์ํ ์ธ๊ฐ์ง๋ฅผ ๊ผฝ์ ์ ์์๋๋ฐ Context,Trigger,Provider ์ ๋๋ค.
๋๋กญ๋ค์ด์ ์ด์๋์ง,๋ซ์๋์ง์ ๊ทธ๋ฆฌ๊ณ ๊ทธ state๋ฅผ ๋ณ๊ฒฝ์ํค๋ ํจ์๋ฅผ ContextAPI๋ฅผ ์ฌ์ฉํด์ ์ ์ญ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ , ์ค์ ๋ก ๋๋กญ๋ค์ด์ ์คํ์ํค๋ ํจ์๋ฅผ Trigger๋ผ๊ณ ํฉ๋๋ค.
- ๋๋กญ๋ค์ด ์คํ์

- ๋๋กญ๋ค์ด ์คํํ

<Dropdown>
<Dropdown.Trigger> // ๋๋กญ๋ค์ด์ ์คํ์ํค๋ ๋ฒํผ (ํน์ ๋ฒํผ์ ๋๋ ์๋ ๋๋กญ๋ค์ด์ด ์ด๋ฆฐ๋ค๋ฉด ๊ทธ ๋ฒํผ์ Trigger๋ผํ๋ค)
<Icon name="more" size={32} />
</Dropdown.Trigger>
<Dropdown.Content className={deleteDropdownContainer}> // ๋๋กญ๋ค์ด์ ๋ค์ด๊ฐ๋ ๋ด์ฉ
<Dropdown.Item
text="์ญ์ ํ๊ธฐ"
onClick={handleDeleteClick}
rightAddon={<Icon name="delete" size={16} />}
></Dropdown.Item>
</Dropdown.Content>
</Dropdown>
์ง์ฅ ์์ ์๋ arrow icon์ด ์ฌ๊ธฐ์ Trigger์ ํด๋น๋ฉ๋๋ค.
import { createContext } from '@linker/react';
interface DropdownContext {
isOpen: boolean;
onOpenChange?: () => void;
}
const context = {
isOpen: false,
onOpenChange: undefined,
};
export const [DropdownProvider, useDropdownContext] = createContext<DropdownContext>(
'Dropdown',
context,
);
์ฐ์ ์ํ๋ถํฐ ์ดํด๋ณผ๊น์?
์ด์๋์ง ์ํ๋ฅผ ์ ์ฅํ๋ isOpen๊ณผ ์ด ๋ณ์๋ฅผ ๋ณ๊ฒฝ์ํค๋ onOpenChange()๋ฅผ ํจ๊ป ์ ์ฅํฉ๋๋ค.
Dropdown.tsx
'use client';
import { HTMLAttributes } from 'react';
import { ReactNode } from 'react';
import { useState } from 'react';
import { dropdownTrigger } from './Dropdown.css';
import DropdownItem from './DropdownItem';
import { DropdownProvider, useDropdownContext } from './context';
interface Props extends HTMLAttributes<HTMLButtonElement> {
children?: ReactNode;
className?: string;
}
const Dropdown = ({ children, className }: Props) => {
const [isOpen, setIsOpen] = useState(false);
return (
<DropdownProvider isOpen={isOpen} onOpenChange={() => setIsOpen((prev) => !prev)}>
<button className={className}>{children}</button>
</DropdownProvider>
);
};
export default Object.assign(Dropdown, {
Item: DropdownItem,
Trigger: DropdownTrigger,
Content: DropdownContent,
});
function DropdownTrigger({ children }: Props) {
const { onOpenChange } = useDropdownContext('Dropdown-Trigger');
return (
<button type="button" onClick={onOpenChange} className={dropdownTrigger}>
{children}
</button>
);
}
function DropdownContent({ children, className }: Props) {
const { isOpen } = useDropdownContext('Dropdow-Trigger');
return <>{isOpen && <button className={className}> {children}</button>}</>;
}
๋๋กญ๋ค์ด ์ปดํฌ๋ํธ๋ฅผ ๋ณด๋ฉด ์ํ๋ฅผ ์ ๋ฌํด์ฃผ๋ Provider๊ฐ ์๋ Dropdown, Dropdown์ ์ฌ๋ ์ญํ ์ ํ๋ DropdownTrigger, Dropdown๋ด๋ถ์ ์ฝํ ํธ๋ฅผ ์ ์ฅํด์ฃผ๋ DropdownContent๊ฐ ์กด์ฌํฉ๋๋ค.
์ฌ๊ธฐ์ ํต์ฌ์ Provider์์ open๋ ์ํ์ onOpenChangeํจ์์ ์ํ๋ฅผ ๊ฐ์ง๋๋ฐ onOpenChange์ ๊ฒฝ์ฐ ()⇒setIsOpen((prev)⇒!open)์ ํตํด Trigger์์ ๋ฒํผ์ ๋๋ฅด๊ฒ ๋๋ฉด onOpenChangeํจ์๊ฐ ํธ์ถ๋ผ์ isOpen๊ฐ์ด ๋ฐ๋๋ค๋ ๊ฒ๋๋ค!
์ฌ์ฉ์ฒ์์๋ ์๋์ ๊ฐ์ด ์ธ ์ ์์ต๋๋ค.
<Dropdown>
<Dropdown.Trigger>
<Icon name="more" size={32} />
</Dropdown.Trigger>
<Dropdown.Content className={deleteDropdownContainer}>
<Dropdown.Item
text="์ญ์ ํ๊ธฐ"
onClick={handleDeleteClick}
rightAddon={<Icon name="delete" size={16} />}
></Dropdown.Item>
</Dropdown.Content>
</Dropdown>
์ด์ ์ฌ์ฉ์ฒ์์๋ ๋๋กญ๋ค์ด์ ์ํ๋ฅผ ๋ชฐ๋ผ๋ ๋๊ณ , ๋น์ฆ๋์ค ๋ก์ง์๋ง ์ง์คํ ์ ์๊ฒ ๋์์ต๋๋ค! ๐
