๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป ํ”„๋กœ์ ํŠธ/๐Ÿ€ํ–‰์šด์˜ ๋กœ๋˜ ๋งˆ๋ฒ•์ง„๐Ÿ›ธ

[React, Next.js] ๋ฆฌ์•กํŠธ์˜ ์—ฌ๋Ÿฌ ์•Œ๋ฆผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ๊ทธ ์ค‘ Sonner ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ฝ”๋“œ ๊ตฌํ˜„ํ•˜๊ธฐ.

by hyeong._.ing 2026. 5. 8.

 

 

ํ•ด๋‹น ํŽ˜์ด์ง€ ์‚ฌ์šฉ์— ๋ช‡ ๊ฐ€์ง€ ๊ทœ์น™์ด ์žˆ๋‹ค.
๊ทธ ๊ทœ์น™์„ ์–ด๊ฒผ์„ ๋•Œ, ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆฌ๊ณ  ์‹ถ๋‹ค.
๋ฆฌ์•กํŠธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด
์‚ฌ์šฉ์ž์—๊ฒŒ ๊ทœ์น™์„ ์•Œ๋ ค๋ณด์ž!

 

 

 

 

 

 

https://lotto-magic-frontend.vercel.app/

 

๋กœ๋˜ ๋ฒˆํ˜ธ ์ƒ์„ฑ ๋งˆ๋ฒ•์ง„

ํ–‰์šด ์š”์†Œ 3๊ฐœ๋ฅผ ์„ ํƒํ•˜๋ฉด ์˜ค๋Š˜์˜ ๋กœ๋˜ ๋ฒˆํ˜ธ์™€ ํ–‰์šด ์ ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์‚ฌ์ดํŠธ์ž…๋‹ˆ๋‹ค.

lotto-magic-frontend.vercel.app

 

 

 

 

 

 

1. ํ™”๋ฉด

 

 

 

 

 

 


 

 

 

 

 

2. ๋‹ค์–‘ํ•œ ์•Œ๋ฆผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • React-toastify
    : ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. ๊ธฐ๋Šฅ์ด ๋งŽ๊ณ  ์•ˆ์ •์ ์ด๋‹ค. ๊ธฐ๋ณธ ์Šคํƒ€์ผ์ด ์žˆ์–ด์„œ ์ปค์Šคํ…€์ด ๋งŽ์ด ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ ํŽธ๋ฆฌํ•˜๋‹ค.

  • Sweetalert2
    : ๊ธฐ์กด์˜ alert ์ฐฝ๋ณด๋‹ค ๋‹ค์–‘ํ•œ ๋””์ž์ธ๊ณผ ์ƒ‰๊ฐ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ alert ์ฐฝ์ด๋‹ค. ํ•œ ์ข…๋ฅ˜๋งŒ ์žˆ์ง€ ์•Š๊ณ  alert, confirm, prompt ์ž…๋ ฅ์ฐฝ ์—ญ์‹œ ์ง€์›ํ•˜๋ฉฐ ์—ฌ๋Ÿฌ ์ฃผ์ œ์— ๋”ฐ๋ฅธ ๋‹ค์–‘ํ•œ ์•Œ๋žŒ์ฐฝ์„ ๋”ฐ๋กœ css ์ž‘์—…์—†์ด ๊ณ ํ€„๋ฆฌํ‹ฐ์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฐฝ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉ์ž์—๊ฒŒ ํ™•์ธ/์ทจ์†Œ๊ฐ€ ํ•„์š”ํ•œ ๋ชจ๋‹ฌ์„ ์‚ฌ์šฉํ•ด์•ผํ•  ๋•Œ ํŽธ๋ฆฌํ•˜๋‹ค. ๊ฐ€๋ฒผ์šด ์•ˆ๋‚ด๋ณด๋‹ค๋Š” ์กฐ๊ธˆ ๋ฌด๊ฑฐ์šด ๋А๋‚Œ์ด ์žˆ๋‹ค.

  • Sonner
    : React์˜ ์„ ์–ธ์  ๊ตฌ์กฐ์— ์ตœ์ ํ™”๋œ ํ† ์ŠคํŠธ์ด๋‹ค. ๊ฐ€๋ฒผ์šฐ๋ฉฐ Framer Motion ์Šคํƒ€์ผ๋กœ ๋ถ€๋“œ๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ตฌํ˜„ํ•œ๋‹ค. Promise ์ฒ˜๋ฆฌ๋กœ ๋กœ์ง์„ ์ž‘์„ฑํ•˜๊ธฐ ๋งค์šฐ ๊ฐ„ํŽธํ•˜๋‹ค. headless ๋ชจ๋“œ๋ฅผ ์ง€์›ํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ๋””์ž์ธํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ์‰ฝ๋‹ค. Tailwind CSS์™€ ๊ถํ•ฉ์ด ์ข‹์€ ํŽธ์ด๋‹ค. 

  • ๊ทธ ์ค‘ Sonner๋ฅผ ์„ ํƒํ–ˆ๋‹ค. ์ผ๋‹จ ์ œ์ผ ํฐ ์ด์œ ๋Š” ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋ชจ์Šต ๊ทธ๋Œ€๋กœ CSS๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ๊ฐ€์žฅ ์ปธ๋‹ค. ์กฐ์ดํ•˜๊ธด ํ•ด๋„ ๋‚˜๋ฆ„ '๋งˆ๋ฒ•'์— ๊ด€๋ จํ•œ ํŽ˜์ด์ง€๋ผ์„œ(?) ์ผ์ •ํ•œ ํ…Œ๋งˆ๋ฅผ ์›ํ–ˆ๋‹ค. ๋˜ ์ด ํ”„๋กœ์ ํŠธ์˜ ๋กœ์ง์€ ์‚ฌ์šฉ์ž์™€ ์ƒํ˜ธ์ž‘์šฉ ์—†์ด ๋ฒˆํ˜ธ๋งŒ ๋ณด์—ฌ์ฃผ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•„์ฃผ ๊ฐ€๋ณ๊ฒŒ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” Sonner๊ฐ€ ์•Œ๋งž๋‹ค๊ณ  ๋А๊ผˆ๋‹ค. ๊ผญ Sonner๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š” ์—†์ด, ๋ณธ์ธ ํ”„๋กœ์ ํŠธ์— ๋งž๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค. ๊ด€๋ จ ๋งํฌ๋Š” ์•„๋ž˜์— ์ฒจ๋ถ€ํ•˜๊ฒ ๋‹ค.

 

 

- React-toastify

 

React์—์„œ react-toastify๋กœ ํšจ๊ณผ์ ์ธ ์•Œ๋ฆผ ๊ตฌํ˜„ํ•˜๊ธฐ

React์—์„œ react-toastify๋กœ ํšจ๊ณผ์ ์ธ ์•Œ๋ฆผ ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์‚ฌ์šฉ์ž์—๊ฒŒ ์ž‘์—…์˜ ์„ฑ๊ณต, ์‹คํŒจ, ์ง„ํ–‰ ์ƒํƒœ ๋“ฑ์„ ์•Œ๋ ค์ค„ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์•Œ๋ฆผ(notification)์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€

hell-of-company-builder.tistory.com

 

 

-SweetAlert2

 

๐ŸŽจ SweetAlert2 - ์ด์œ alert ๋ชจ๋‹ฌ์ฐฝ ์„ค์น˜ & ์‚ฌ์šฉ๋ฒ•

SweetAlert2 ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์›น ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์ž์ฃผ Alert ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. Alert๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆผ์„ ์ฃผ๊ณ ์ž ํ•  ๋•Œ ์ •๋ง ์ž๊ตฌ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž๋ฐ”์Šคํฌ๋ฆฝ

inpa.tistory.com

 

 

- React์— ์ ์šฉํ•˜๊ธฐ ์ข‹์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ชจ์Œ

 

[๋ฒˆ์—ญ] ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐ•ํ™”ํ•  ์ˆ˜ ์žˆ๋Š” 17๊ฐœ React ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Let's Code Future ๋‹˜์˜ 25.01.20์ผ์ž ํฌ์ŠคํŠธ ์˜ ๋ฒˆ์—ญ๊ธ€์ž…๋‹ˆ๋‹ค https://medium.com/@letscodefuture/top-16-modern-react-libraries-to-supercharge-your-next-big-project-78e912e95014 Top 16+ Modern React Libraries To Supercharge Your Next Big Proje

daunje0.tistory.com

 

 

 

 


 

 

 

 

3. Sonner

  • Sonner ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜
npm install sonner

 

 

  • ํ† ์ŠคํŠธ ๋งŒ๋“ค ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ
    ๋‚ด๊ฒฝ๋กœ: components/common/MagicToast.tsx

 

 

  • ํ† ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ
    1) ์ „์ฒด ์ฝ”๋“œ
'use client';

import { Toaster, toast } from 'sonner';

type MagicToastOptions = {
    duration?: number;
};

export function showMagicToast(
    message: string,
    options?: MagicToastOptions
) {
    toast.custom(
        (toastId) => (
            <button
                type="button"
                onClick={() => toast.dismiss(toastId)}
                style={{
                    width: 'min(286px, calc(100vw - 48px))',
                    minHeight: '52px',
                    padding: '14px 22px',
                    transform: 'translateX(12.5%)',
                    border: 'none',
                    borderRadius: '28px',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    textAlign: 'center',
                    cursor: 'pointer',
                    background:
                        'linear-gradient(90deg, rgba(181, 162, 242, 0.96) 0%, rgba(193, 232, 252, 0.96) 100%)',
                    color: '#111111',
                    fontSize: 'clamp(0.88rem, 3.6vw, 1.08rem)',
                    fontWeight: 700,
                    lineHeight: 1.25,
                    fontFamily: 'OngleipParkDahyeon, sans-serif !important',
                    boxShadow:
                        '0 16px 38px rgba(134, 104, 214, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.55)',
                    backdropFilter: 'blur(6px)',
                }}
            >
                {message}
            </button>
        ),
        {
            duration: options?.duration ?? 1700,
            position: 'top-center',
        }
    );
}

export function MagicToaster() {
    return (
        <Toaster
            position="top-center"
            duration={1900}
            visibleToasts={2}
            gap={14}
            offset={70}
        />
    );
}

 

 

       2) ์„ค๋ช… ํฌํ•จ๋œ ์ฝ”๋“œ

'use client';

import { Toaster, toast } from 'sonner';

// showMagicToast ํ•จ์ˆ˜์— ์ถ”๊ฐ€๋กœ ๋„ฃ์„ ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์˜ ๋ชจ์–‘์„ ์ •ํ•ด๋’€๋‹ค.
type MagicToastOptions = {
    // ํ˜„์žฌ ์˜ต์…˜์€ ํ•˜๋‚˜๋งŒ ์„ค์ •ํ–ˆ๋‹ค.
    // ?์„ ๋ถ™์—ฌ์„œ duration์€ ์„ ํƒ๊ฐ’์œผ๋กœ ์žˆ์–ด๋„ ๋˜๊ณ  ์—†์–ด๋„ ๋œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
    // showMagicToast('์š”์†Œ๋ฅผ 3๊ฐœ ์ด์ƒ ์„ ํƒํ•ด์ฃผ์„ธ์š”.', {duration: 3000,});
    // ๋งŒ์•ฝ ํŠน์ • ํ† ์ŠคํŠธ๋งŒ 3000์œผ๋กœ ์„ค์ •ํ•˜๋ฉด 3์ดˆ๊ฐ€ ๋ณด์ด๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
    // ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์•„๋ž˜ ์„ค์ •ํ•œ ๊ฐ’์œผ๋กœ ๋ณด์ธ๋‹ค.(1.7์ดˆ)
    duration?: number;
};

// ๋‹ค๋ฅธ ์ปดํฌ๋„ˆํ‹‘์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก export ํ–ˆ๋‹ค.
export function showMagicToast(
    // showMagicToast ํ•จ์ˆ˜๊ฐ€ ๋ฐ›์„ ๊ฐ’๋“ค์„ ์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.
    // showMagicToast(1_message, 2_MagicToastOption)์ด ๋œ๋‹ค.
    message: string,
    options?: MagicToastOptions
) {
    toast.custom(
        (toastId) => (
            <button
                type="button"
                onClick={() => toast.dismiss(toastId)}
                style={{
                    width: 'min(286px, calc(100vw - 48px))',
                    minHeight: '52px',
                    padding: '14px 22px',
                    transform: 'translateX(12.5%)',
                    border: 'none',
                    borderRadius: '28px',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    textAlign: 'center',
                    cursor: 'pointer',
                    background:
                        'linear-gradient(90deg, rgba(181, 162, 242, 0.96) 0%, rgba(193, 232, 252, 0.96) 100%)',
                    color: '#111111',
                    fontSize: 'clamp(0.88rem, 3.6vw, 1.08rem)',
                    fontWeight: 700,
                    lineHeight: 1.25,
                    fontFamily: 'OngleipParkDahyeon, sans-serif !important',
                    boxShadow:
                        '0 16px 38px rgba(134, 104, 214, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.55)',
                    backdropFilter: 'blur(6px)',
                }}
            >
                {/* ์ „๋‹ฌ๋ฐ›์€ message๋ฅผ ํ† ์ŠคํŠธ ์•ˆ์— ํ‘œ์‹œํ•œ๋‹ค. */}
                {message}
            </button>
        ),
        {
            // ํ† ์ŠคํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ์‚ฌ๋ผ์ง€๊ธฐ๊นŒ์ง€์˜ ์‹œ๊ฐ„์ด๋‹ค.(1.7์ดˆ)
            // options ์•ˆ์— duration์ด ์žˆ์œผ๋ฉด ๊ทธ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ณ 
            // ์—†์œผ๋ฉด 1700ms๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
            duration: options?.duration ?? 1700,
            position: 'top-center',
        }
    );
}

// MagicToaster๋Š” ์‹ค์ œ ํ† ์ŠคํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๊ณต๊ฐ„์„ ๋งŒ๋“œ๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.
// Next.js์˜ ๊ฒฝ์šฐ layout.tsx์— ๋„ฃ์–ด ์•ฑ ์ „์ฒด์—์„œ ํ•œ ๋ฒˆ๋งŒ ๋ Œ๋”๋งํ•˜๋ฉด ๋œ๋‹ค.
export function MagicToaster() {
    return (
        <Toaster
            position="top-center"
            duration={1700}
            // ๋™์‹œ์— ๋ณด์ผ ์ˆ˜ ์žˆ๋Š” ํ† ์ŠคํŠธ ํ™”๋ฉด ๊ฐœ์ˆ˜
            // ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ์—ฐ์†์œผ๋กœ ํด๋ฆญํ•ด๋„
            // ํ† ์ŠคํŠธ๊ฐ€ 2๊ฐœ ์ด์ƒ์œผ๋กœ ๋ณด์ด์ง€ ์•Š๊ฒŒ ๋ง‰์•˜๋‹ค.
            visibleToasts={2}
            // ํ† ์ŠคํŠธ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ๋ณด์ผ ๋•Œ ๋‘˜ ์‚ฌ์ด์˜ ๊ฐ„๊ฒฉ์ด๋‹ค.
            gap={14}
            // ํ™”๋ฉด์—์„œ ์–ผ๋งˆ๋‚˜ ๋–จ์–ด๋œจ๋ฆด์ง€ ์„ค์ •ํ–ˆ๋‹ค.
            // top-center๋ฅผ ๋ฏธ๋ฆฌ ์„ค์ •ํ–ˆ์œผ๋‹ˆ ๋งจ ์œ„์—์„œ 70px ์•„๋ž˜๋กœ ํ‘œ์‹œ๋œ๋‹ค.
            offset={70}
        />
    );
}

 

 

 

 


 

 

 

 

4. showMagicToast ์ฝ”๋“œ์— ์ ์šฉํ•˜๊ธฐ

  • ์š”์†Œ๋ฅผ 3๊ฐœ ์ด์ƒ ์„ ํƒํ–ˆ์„ ๋•Œ
        if (selectedOptions.length >= 3) {
            showMagicToast('์š”์†Œ๋Š” 3๊ฐœ๊นŒ์ง€๋งŒ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด์š”.');
            return;
        }
MagicToast.tsx์—์„œ message: string, options?: MagicToastOptions ์ด ์ฝ”๋“œ๋ฅผ ์ •์˜ํ–ˆ๋‹ค. ์„ค๋ช…์œผ๋กœ showMagicToast(1_message, 2_MagicToastOption)๊ฐ€ ๋˜๊ณ  ์—ฌ๊ธฐ์„œ ๋‘๋ฒˆ์งธ์— duration: 3000๊ณผ ๊ฐ™์€ ์ž…๋ ฅ์„ ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ 1700์ด ๋œ๋‹ค๊ณ  ํ–ˆ๋‹ค. 

๋‹ค์‹œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž. ๋ฉ”์‹œ์ง€๋งŒ ์ ์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋Š” ๊ธฐ๋ณธ๊ฐ’์ธ 1.7์ดˆ ๋™์•ˆ ๋ณด์ด๊ณ  ์‚ฌ๋ผ์ง„๋‹ค.

 

        if (selectedOptions.length >= 3) {
            showMagicToast('์š”์†Œ๋ฅผ 3๊ฐœ ์ด์ƒ ์„ ํƒํ•ด์ฃผ์„ธ์š”.', {duration: 3000,});
            return;
        }
์—ฌ๊ธฐ์„œ๋Š” ๋ฉ”์‹œ์ง€์™€ duration์„ ํ•จ๊ป˜ ๋ณด๋ƒˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋Š” ๋”ฐ๋กœ ์„ค์ •ํ•œ 3์ดˆ ๋™์•ˆ ๋ณด์ด๊ณ  ์‚ฌ๋ผ์งˆ ๊ฒƒ์ด๋‹ค. ์ด๋Ÿฐ์‹์œผ๋กœ ํ† ์ŠคํŠธ์˜ ๋ฉ”์‹œ์ง€์™€ ๋ณด์—ฌ์ค„ ์‹œ๊ฐ„์„ ์ž…๋ ฅํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. 

 

 

 

 


 

 

 

 

4. layout.tsx

// MagicToaster๋Š” ์‹ค์ œ ํ† ์ŠคํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๊ณต๊ฐ„์„ ๋งŒ๋“œ๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.
// Next.js์˜ ๊ฒฝ์šฐ layout.tsx์— ๋„ฃ์–ด ์•ฑ ์ „์ฒด์—์„œ ํ•œ ๋ฒˆ๋งŒ ๋ Œ๋”๋งํ•˜๋ฉด ๋œ๋‹ค.
export function MagicToaster() {
    return (
		...
        />
    );
}
return (
        <html lang="ko">
        <body className={`${geistSans.variable} ${geistMono.variable}`}>
        <MswProvider>
            <QueryProvider>
                {children}
            </QueryProvider>
            
            <MagicToaster />
        </MswProvider>
        </body>
        </html>
    );
}
MagicToast.tsx์— ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์„ ๋ณด๋ฉด MagicToaster ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค. MagicToaster๋Š” ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ์ง์ ‘ ๋„์šฐ๋Š” ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ, ํ† ์ŠคํŠธ๊ฐ€ ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•ด์ฃผ๋Š” ์ถœ๋ ฅ ๊ณต๊ฐ„์ด๋‹ค. ๊ทธ๋ž˜์„œ ์•ฑ ์ „์ฒด์— ํ† ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก layout.tsx์˜ children ์•„๋ž˜์—<MagicToaster/>๋ฅผ ๋„ฃ์—ˆ๋‹ค.

๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ MswProvider์™€ ๊ฐ™์ด {children}์„ ๊ฐ์‹ผ ํ˜•ํƒœ๊ฐ€ ์•„๋‹Œ ์ด์œ ๋Š”, MagicToaster๊ฐ€ children์—๊ฒŒ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” provider ์—ญํ• ์„ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ† ์ŠคํŠธ๋Š” ๋‹จ์ˆœํžˆ ์•Œ๋ฆผ์ด ๋œฐ ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฐ„๋งŒ ์„ค์น˜ํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ๊ตณ์ด children์„ ๊ฐ์Œ€ ํ•„์š”๊ฐ€ ์—†๋‹ค.

ํ† ์ŠคํŠธ๋Š” ํŠน์ • ํŽ˜์ด์ง€์˜ ์ผ๋ถ€๋ผ๊ธฐ๋ณด๋‹ค๋Š” ์•ฑ ์ „์ฒด์— ๋– ๋‹ค๋‹ˆ๋Š” ์ „์—ญ ์•Œ๋ฆผ์ด๋‹ค. ์ด ์•Œ๋ฆผ์€ ํŽ˜์ด์ง€ ์•ˆ์ชฝ ๋ฐ•์Šค์— ๋“ค์–ด๊ฐ€๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ํ™”๋ฉด ์ƒ๋‹จ์— ๋‘ฅ์‹ค ๋– ์•ผํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ํŠน์ • ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ๋„ฃ๊ธฐ๋ณด๋‹ค layout.tsx์— ์ „์—ญ์œผ๋กœ ํ•œ ๋ฒˆ ๋„ฃ๋Š”๊ฒŒ ์ข‹๋‹ค.