[Next.js] ํ—ค๋“œ๋ฆฌ์Šค ์ปดํฌ๋„ŒํŠธ๋กœ ๋“œ๋กญ๋‹ค์šด ๋งŒ๋“ค๊ธฐ!

2024. 2. 14. 14:57ยทNext.js & React

๐Ÿ‘ฉ๐Ÿป‍๐ŸŽจ ๋ณดํ†ต์˜ ๋“œ๋กญ๋‹ค์šด ๋งŒ๋“ค๊ธฐ

๋ณดํ†ต ๋“œ๋กญ๋‹ค์šด์„ ๋งŒ๋“ ๋‹ค๊ณ  ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค๊นŒ์š”?

{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>

 

์ด์ œ ์‚ฌ์šฉ์ฒ˜์—์„œ๋Š” ๋“œ๋กญ๋‹ค์šด์˜ ์ƒํƒœ๋ฅผ ๋ชฐ๋ผ๋„ ๋˜๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ˜Š

'Next.js & React' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[NextJS] App router์—์„œ Emotion์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š” ์ด์œ ์™€ React Streaming SSR์„ ๊ณ๋“ค์ธ  (6) 2025.06.16
[React] Controlled input๊ณผ Uncontrolled input์€ ํ˜ผ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค!  (1) 2025.04.29
'Next.js & React' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [NextJS] App router์—์„œ Emotion์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š” ์ด์œ ์™€ React Streaming SSR์„ ๊ณ๋“ค์ธ
  • [React] Controlled input๊ณผ Uncontrolled input์€ ํ˜ผ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค!
jjungking
jjungking
์ฉกํ‚น์˜ ๊ณ ์ƒํ•œ ์ฝ”๋”ฉ ์ด์•ผ๊ธฐ
  • jjungking
    jjungking
    jjungking
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (19)
      • Cloud (2)
      • K8S & Docker (4)
      • Linux (3)
      • Next.js & React (3)
      • SpringBoot (2)
      • OS (0)
      • Network (1)
      • AWS (1)
      • Git (1)
      • OpenSource (1)
      • ํšŒ๊ณ ๋ก (1)
      • ๊ธฐ์ˆ ์„ธ์…˜ ๊ณต๋ถ€ํ•˜๊ธฐ (0)
      • Certi (0)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

    • ๊นƒํ—ˆ๋ธŒ
  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    ec2๋А๋ฆด๋•Œ
    HikariCP
    RDS
    NCP
    ์˜คํ”ˆ์†Œ์Šค๊ธฐ์—ฌ
    objectstorage
    nks
    k8s
    AWS
    ๋„ค์ด๋ฒ„ํด๋ผ์šฐ๋“œํ”Œ๋žซํผ
    aws์ด๊ด€
    promtail
    ๋„ค์ด๋ฒ„ํด๋ผ์šฐ๋“œ
    githook
    Husky
    cronjob
    rds์ด๊ด€
    springboot
    ReactHookForm
    uvicorn
    Helm
    http์‘๋‹ต๋А๋ฆด๋•Œ
    uncontrolledinput
    Grafana
    Nclouder
    ๋ฆฌ๋ˆ…์Šค์‹œ์Šคํ…œํ”„๋กœ๊ทธ๋ž˜๋ฐ
    ncloud
    controlledInput
    Loki
    ec2
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.2
jjungking
[Next.js] ํ—ค๋“œ๋ฆฌ์Šค ์ปดํฌ๋„ŒํŠธ๋กœ ๋“œ๋กญ๋‹ค์šด ๋งŒ๋“ค๊ธฐ!
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”