🪟 React에서 모달/다이얼로그 시스템 설계 및 Context 관리 전략
React 앱을 개발하다 보면 거의 반드시 등장하는 UI 요소가 있습니다. 바로 모달(Modal) 또는 다이얼로그(Dialog)입니다.
경고창, 설정창, 상세정보 보기 등 다양한 목적의 모달은 그 자체로도 중요하지만, 더 중요한 건 “어떻게 관리할 것인가”입니다.
이번 글에서는 다음과 같은 상황을 해결할 수 있는 전략을 중점적으로 다룹니다
- 전역에서 모달을 띄우고 닫을 수 있는 구조
- 여러 종류의 모달을 동적으로 다루는 방법
- Context와 Portal을 활용한 확장 가능한 설계
🎯 1. 왜 전역 모달 관리가 필요한가?
기본적인 모달은 보통 아래와 같이 작성됩니다:
{`{isOpen && setOpen(false)} />} `}
하지만 다음과 같은 문제점이 발생합니다:
- 모달을 띄우기 위한
isOpen
상태가 각 페이지마다 분산됨 - 중첩된 모달이나 다이얼로그가 생기면 관리가 복잡해짐
- 컴포넌트 간의 깊은 props 전달 필요 (props drilling)
이럴 때는 전역 모달 컨텍스트를 만들어
언제 어디서든 모달을 띄우고 닫을 수 있는
구조로 관리하는 것이 훨씬 유리합니다.
🧱 2. 전역 모달 시스템의 핵심 구조
전역 모달 시스템의 핵심은 다음 3가지입니다:
- ModalContext: 현재 열린 모달과 제어 함수들을 담은 전역 상태
- ModalProvider: Context를 감싸고 모달을 Portal로 렌더링
- useModal Hook: 컴포넌트 어디서든 모달을 띄울 수 있도록 제공
1) Context 정의
{`const ModalContext = React.createContext(null);`}
2) Provider 구현
{`function ModalProvider({ children }) {
const [modal, setModal] = useState(null);
const openModal = (Component, props) => {
setModal({ Component, props });
};
const closeModal = () => {
setModal(null);
};
return (
{children}
{modal && (
)}
);
}`}
3) useModal Hook
{`function useModal() {
const context = useContext(ModalContext);
if (!context) throw new Error('ModalProvider 내부에서 사용하세요');
return context;
}`}
4) Portal 구현 (예: 모달 root에 랜더링)
{`const ModalPortal = ({ children }) => {
const el = document.getElementById('modal-root');
return createPortal(children, el);
};`}
이 구조를 기반으로, 어떤 컴포넌트에서도 다음처럼 사용할 수 있습니다:
{`const { openModal } = useModal();
openModal(MyDialog, { title: '알림', message: '정말 삭제하시겠습니까?' });`}
📦 3. 다이얼로그 종류가 많을 때는?
복잡한 앱에서는 Alert, Confirm, Custom 등 다양한 다이얼로그가 필요합니다.
이때는 모달 이름과 매핑된 컴포넌트를 관리하는 방식으로 확장할 수 있습니다.
모달 등록 방식 예시
{`const MODAL_COMPONENTS = {
'ALERT_MODAL': AlertModal,
'CONFIRM_MODAL': ConfirmModal,
'FORM_MODAL': FormModal,
};`}
{`const openModal = (modalName, props) => {
const Component = MODAL_COMPONENTS[modalName];
if (!Component) return;
setModal({ Component, props });
};`}
이렇게 하면 문자열 키만 넘겨도 원하는 모달을 띄울 수 있어 유지보수성과 가독성이 크게 향상됩니다.
🧠 4. 모달 속 상태/로직은 어디서 관리할까?
모달 안에서 폼을 작성하거나 API를 호출하는 경우도 많습니다.
이때 상태를 모달 외부에서 관리하면 너무 복잡해지고, 내부에서만 관리하면 재사용성이 떨어집니다.
따라서 다음 기준으로 판단하는 것이 좋습니다:
- 다시 열 때 초기화되어야 하는 상태: 모달 내부 useState
- 부모 컴포넌트와 동기화돼야 하는 상태: Props로 전달
- 다수 모달 간 공유해야 하는 상태: 전역 상태관리 (예: Redux, Zustand)
예시
{`openModal(EditProfileModal, { userId: 123, onComplete: refetchUser });`}
→ 부모에서 필요한 액션은 prop으로 전달하고, 나머지는 내부에서 처리하는 방식이 적절합니다.
🧪 5. 모달 테스트와 UX 향상 팁
모달도 결국 하나의 UI 컴포넌트입니다. 따라서 다음과 같은 UX 요소를 고려하는 것이 좋습니다:
- ESC 키로 닫기
- 바깥 영역 클릭 시 닫기
- 포커스 트랩: 모달 내 포커스만 이동하게
- ARIA 속성: 접근성 향상
예를 들어 ESC 키 닫기 기능은 아래처럼 구현할 수 있습니다:
{`useEffect(() => {
const onKeyDown = (e) => {
if (e.key === 'Escape') onClose();
};
window.addEventListener('keydown', onKeyDown);
return () => window.removeEventListener('keydown', onKeyDown);
}, []);`}
✅ 마무리 요약
React에서 모달 시스템을 제대로 설계하면 UI의 유연성과 유지보수성이 크게 향상됩니다.
특히 중대형 프로젝트일수록 전역 Context + Portal 기반 설계는 필수가 됩니다.
전략 | 핵심 요약 |
---|---|
전역 관리 | Context + Provider로 전역 모달 상태 관리 |
Portal 활용 | DOM 최상단에 렌더링해 위치 제어 |
유연한 호출 | openModal(Component, props) 또는 openModal(key, props) |
상태 관리 전략 | Props vs 내부 State vs 전역 상태 구분 |
UX 고려 | ESC, 배경 클릭 닫기, 포커스트랩, 접근성 |
모달 시스템은 단순 UI가 아니라 앱의 중앙 제어 센터처럼 다뤄야 합니다.
이 글을 바탕으로 여러분만의 견고한 모달 시스템을 구축해보세요! 🚀
'일상이 개발' 카테고리의 다른 글
React Toast 시스템 설계 가이드 – Notification 알림을 전역에서 관리하는 법 (0) | 2025.04.15 |
---|---|
[개발 가이드] 외부 협업을 위한 HTML, CSS, JavaScript, React 프로젝트 기준 총정리 (0) | 2025.04.14 |
React 디자이너 협업을 위한 컴포넌트 작성 전략 – 디자인 시스템 기반 실전 가이드 (0) | 2025.04.12 |
React 공통 컴포넌트 테스트 자동화 전략 – 안정적인 UI를 위한 실전 가이드 (0) | 2025.04.12 |
React 앱에서 성능 병목 찾기: DevTools, why-did-you-render, Profiler 실전 분석 (0) | 2025.04.11 |