ABOUT ME

-

  • [ Next ] Alert, Confirm 커스텀 Hook
    Front/Next 2025. 12. 5. 13:47
    반응형

    alert이나 confirm을 직접 커스텀하여 만들려고 하기에
    직접 커스텀 hook을 만들어서 사용했다.

     

    context는 전역 데이터를 전달하기 위한 것이며 provider를 통해 값을 넣어준다.

    provider는 context에 값을 넣어주는 역할을 하며, provider로 감싼 범위 안에 있는 컴포넌트들이 context에 있는 값에 접근 할 수 있도록 해준다.

    hook은 provider가 context에 넣은 값을 가져오는 함수 역할을 해준다.

     

     


    Context

     

    데이터를 저장할 context생성

    alert과 confrim만 사용하기에 alert과 confirm 함수를 받을 수 있도록 타입을 정의

    import { createContext } from "react";
    
    export interface DialogContextType {
        alert: (message: string) => Promise<void>;
        confirm: (message: string) => Promise<boolean>;
    }
    
    export const DialogContext = createContext<DialogContextType | null>(null);

     


    Provider &  Component

    전역에서 사용할 수 있도록 provider를 만들어주고 적용

     

    alert과 confirm에 따라서 modal 컴포넌트에서 분기하여 다르게 화면에 표시

     

    이때 사용자가 선택한 버튼의 결과를 return해줘야하므로 promise로 return 해준다.

     

    이후 context.provider를 통해 context에 alert,confirm 함수를 저장

    "use client"
    
    import { useState } from "react";
    import { DialogContext } from "./DialogContext";
    import DialogModal from "./DialogModal";
    
    export function DialogProvider({ children }: { children: React.ReactNode }) {
    
        const [options, setOptions] = useState<any>(null);
        const [resolver, setResolver] = useState<(value: any) => void>();
    
        const alert = (message: string) => {
            return new Promise<void>((resolve) => {
                setResolver(() => resolve);
                setOptions({ type: "alert", message });
            });
        };
    
        const confirm = (message: string) => {
            return new Promise<boolean>((resolve) => {
                setResolver(() => resolve);
                setOptions({ type: "confirm", message });
            });
        };
    
        const handleClose = (result: any) => {
            setOptions(null);
            resolver?.(result);
        };
    
        return (
            <DialogContext.Provider value={{ alert, confirm }}>
                {children}
    
                {options && (
                    <DialogModal
                        type={options.type}
                        message={options.message}
                        onClose={handleClose}
                    />
                )}
            </DialogContext.Provider>
        );
    }

     

    DialogModal 컴포넌트에서는 들어온 타입에 따라서

    alert과 confrim이 각각 다르게 나오도록 처리

        {type === "alert" && (
                        <div className="cursor-pointer bg-[#477082] hover:bg-[#687E88] p-2 rounded-lg text-white w-24 text-center" onClick={() => onClose(true)}>확인</div>
                    )}
    
                    {type === "confirm" && (
                        <div className="flex gap-2.5">
                            <div className="cursor-pointer bg-[#477082] hover:bg-[#687E88] p-2 rounded-lg text-white w-24 text-center" onClick={() => onClose(true)}>확인</div>
                            <div className="cursor-pointer p-2 rounded-lg w-24 text-center bg-gray-200 hover:bg-gray-300" onClick={() => onClose(false)}>취소</div>
                        </div>
                    )}

     

    alert과 confirm은 어디서든 사용할 수 있어야하므로

    RootLayout.tsx에 감싸주었다.

    export default function RootLayout({
      children,
    }: Readonly<{
      children: React.ReactNode;
    }>) {
        return (
        <html lang="ko" suppressHydrationWarning>
            <body>
            <DialogProvider>
                {children}
            </DialogProvider>
            </body>
        </html>
      );
    }

    Hook

    context와 provider를 만들어서 적용 했으니 이제 실제로 사용하기 위해 커스텀 hook을 생성

     

    실제 사용하는 곳에서 useDialog를 호출하면
    useContext로 dialogContext에 저장된 값을 가져올 수 있게 된다.

    export const useDialog = () => {
        const ctx = useContext(DialogContext);
        if (!ctx) throw new Error("useDialog must be used within DialogProvider");
        return ctx;
    };

    Useage

    export default function Test() {
        const dialog = useDialog()
    
    
        const onClickAlert = async () => {
            const result = await dialog.alert("alert")
            console.log("alert : " + result)
        }
    
        const onClickConfirm = async () => {
            const result = await dialog.confirm("confirm")
            console.log("confirm : " + result)
        }
        return (
            <div className="flex flex-col w-full h-full p-2.5">
                <Button onClick={onClickAlert}>alert</Button>
                <Button onClick={onClickConfirm}>confirm</Button>
            </div>
        )
    }

    그러면 console에 확인버튼을 누르면 true가 return 되고 취소를 누르면 false가 return 되는 것을 확인할 수 있다.

    728x90
    반응형