코드 출처 : https://github.com/Cluster-Taek/next14-boilerplate
GitHub - Cluster-Taek/next14-boilerplate
Contribute to Cluster-Taek/next14-boilerplate development by creating an account on GitHub.
github.com
import AuthProvider from './auth-provider';
import ModalProvider from './modal-provider';
import { QueryProvider } from './query-provider';
import SessionProvider from '@/contexts/session-provider';
interface ICoreProviderProps {
children?: React.ReactNode;
}
const CoreProvider = ({ children }: ICoreProviderProps) => {
return (
<SessionProvider>
<AuthProvider>
<QueryProvider>
<ModalProvider>{children}</ModalProvider>
</QueryProvider>
</AuthProvider>
</SessionProvider>
);
};
export default CoreProvider;
ModalProvider
'use client';
import React, { createContext, useCallback, useEffect, useState } from 'react';
export interface ModalComponentType {
id: React.Key;
component: React.ReactNode;
}
interface ModalContextType {
openedModals: ModalComponentType[];
openModal: (modalComponent: ModalComponentType) => void;
closeModal: (id: React.Key) => void;
}
interface ModalContextProps {
children: React.ReactNode;
}
export const ModalContext = createContext<ModalContextType>({} as ModalContextType);
const ModalProvider: React.FC<ModalContextProps> = ({ children }) => {
const [openedModals, setOpenedModals] = useState<ModalComponentType[]>([]);
const openModal = useCallback((props: ModalComponentType) => {
setOpenedModals((modals) => {
return [...modals, { ...props }];
});
}, []);
const closeModal = useCallback((id: React.Key) => {
setOpenedModals((modals) => {
return modals.filter((modal) => modal.id !== id);
});
}, []);
useEffect(() => {
document.body.style.overflow = openedModals.length > 0 ? 'hidden' : 'auto';
return () => {
document.body.style.overflow = 'auto';
};
}, [openedModals]);
useEffect(() => {
const handleRouteChange = () => {
setOpenedModals([]);
};
window.addEventListener('popstate', handleRouteChange);
return () => {
window.removeEventListener('popstate', handleRouteChange);
};
}, []);
return (
<ModalContext.Provider
value={{
openedModals,
openModal,
closeModal,
}}
>
{children}
</ModalContext.Provider>
);
};
export default ModalProvider;
전역적으로 모달의 열림/닫힘 상태를 관리하고, 동적 모달 컴포넌트를 쉽게 추가 및 제거할 수 있습니다.
ModalComponentType 인터페이스
'use client';
import React, { createContext, useCallback, useEffect, useState } from 'react';
export interface ModalComponentType {
id: React.Key;
component: React.ReactNode;
}
- 모달의 ID와 렌더링할 React 컴포넌트를 정의.
- id: 각 모달을 고유하게 식별.
- component: 렌더링할 실제 모달 컴포넌트.
ModalContextType 인터페이스
interface ModalContextType {
openedModals: ModalComponentType[];
openModal: (modalComponent: ModalComponentType) => void;
closeModal: (id: React.Key) => void;
}
- 컨텍스트에서 제공할 데이터와 메서드 정의.
- openedModals: 현재 열려 있는 모달의 배열.
- openModal: 새로운 모달 열기 함수.
- closeModal: 특정 모달 닫기 함수.
ModalContext 생성
export const ModalContext = createContext<ModalContextType>({} as ModalContextType);
- 모달 상태와 관련된 데이터 및 메서드를 공유하기 위한 컨텍스트.
ModalProvider 컴포넌트
const ModalProvider: React.FC<ModalContextProps> = ({ children }) => {
const [openedModals, setOpenedModals] = useState<ModalComponentType[]>([]);
- openedModals: 현재 열려 있는 모달을 상태로 관리.
openModal
const openModal = useCallback((props: ModalComponentType) => {
setOpenedModals((modals) => [...modals, { ...props }]);
}, []);
- 새로운 모달을 openedModals 배열에 추가.
closeModal
const closeModal = useCallback((id: React.Key) => {
setOpenedModals((modals) => modals.filter((modal) => modal.id !== id));
}, []);
- 특정 ID를 가진 모달을 openedModals 배열에서 제거.
useEffect로 스크롤 비활성화
useEffect(() => {
document.body.style.overflow = openedModals.length > 0 ? 'hidden' : 'auto';
return () => {
document.body.style.overflow = 'auto';
};
}, [openedModals]);
- 모달이 열려 있을 때 body 스크롤을 비활성화.
- 모달이 닫히면 스크롤을 다시 활성화.
useEffect로 라우트 변경 시 모달 닫기
useEffect(() => {
const handleRouteChange = () => {
setOpenedModals([]);
};
window.addEventListener('popstate', handleRouteChange);
return () => {
window.removeEventListener('popstate', handleRouteChange);
};
}, []);
- 브라우저 popstate 이벤트(뒤로 가기/앞으로 가기) 발생 시 모든 모달을 닫음.
ModalContext.Provider
return (
<ModalContext.Provider
value={{
openedModals,
openModal,
closeModal,
}}
>
{children}
</ModalContext.Provider>
);
- openedModals, openModal, closeModal 메서드를 컨텍스트로 제공.
- 하위 컴포넌트에서 이 데이터를 사용할 수 있음.
'개발 공부 > React' 카테고리의 다른 글
| Next.js 에서 모달 띄우기와 서버작업을 통한 유저 정보 받기 및 등록 (2) (0) | 2025.01.03 |
|---|---|
| Next.js 에서 모달 띄우기와 서버작업을 통한 유저 정보 받기 및 등록 (1) (1) | 2025.01.02 |
| Next.js에서 레이아웃 구성 (2) / QueryProvider (0) | 2024.12.26 |
| Next.js에서 레이아웃 구성 (1) / SessionProvider, AuthProvider (1) | 2024.12.25 |
| Next.js에서 레이아웃 구성하기 (0) | 2024.12.22 |