230809 React Zustand Modal 전역 상태 관리하기
- Zustand Store: 모달 컴포넌트 정보를 Map 객체로 저장
- 커스텀 훅: Modal을 open,close하는 함수를 만들어서 제공
- 사용자: 커스텀 훅의 open 함수와 close 함수를 사용해 모달을 조작
1. Zustand로 useOverlayStore 생성
overlays 변수: {id:itemElement} 형식으로 오버레이할 모달 컴포넌트를 맵 객체로 저장
addOverlay 함수: 추가할 오버레이 컴포넌트와 id값을 받아 overlays에 추가
deleteOverlay 함수: 오버레이한 컴포넌트 id값을 인자로 받아 delete 메서드로 overlays에서 제거
const useOverlayStore = create<OverlayStore>()(
devtools((set) => ({
overlays: new Map(),
addOverlay: (overlayId, overlayItem) => {
set((state) => {
const overlays = new Map(state.overlays);
overlays.set(overlayId, overlayItem);
return { overlays };
});
},
deleteOverlay: (overlayId) => {
set((state) => {
const overlays = new Map(state.overlays);
overlays.delete(overlayId);
return { overlays };
});
},
}))
);
2. OverlayRoot 컴포넌트에서 오버레이 컴포넌트들 렌더링
overlays 변수에 오버레이할 컴포넌트 정보가 들어있으므로 가져와서 렌더링한다
다른 요소들보다 항상 위에 위치하도록 레이아웃 컴포넌트같은 최상위 위치에서 렌더링 시키는 것이 좋다
const OverlayRoot = () => {
const { overlays } = useOverlayStore((state)=>state)
return (
<>
{[...overlays.entries()].map(([id, element]) => (
<Fragment key={id}>{element}</Fragment>
))}
</>
)
}
3. useOverlay 커스텀 훅 만들기
overlayId값은 오버레이 컴포넌트 구분을 위해 react의 useId() 함수를 사용
open 함수안에서 close() 함수를 넘겨 줌으로써,
사용자가 open 함수를 호출할때 close함수를 오버레이할 컴포넌트에 넣을 수 있다.
이렇게 하면 오버레이할 컴포넌트가 close함수를 호출할 수 있다.
const useOverlay = () => {
const { addOverlay, deleteOverlay } = useOverlayStore(state => state);
const overlayId = useId();
return {
open: (OverlayElement: OverlayElement) => {
setTimeout(
() => addOverlay(overlayId,
OverlayElement({ close: () => deleteOverlay(overlayId) })),
0
);
},
close: () => {
deleteOverlay(overlayId);
}
};
};
4. useOverlay()를 사용해 Modal 열고 닫기
useOverlay의 open 함수를 사용하여 close 함수를 빼내서 AlertModal의 onClose 속성에 넘겨 준다.
AlertModal에서는 Modal의 바깥 영역을 클릭하거나 확인 버튼을 눌렀을때 onClose() 함수를 호출하게 된다.
const overlay = useOverlay();
const openPromiseAlert = () => new Promise((resolve) => {
overlay.open(({close})=>(
<AlertModal
onClose={() => {
resolve(true)
close()
}}
/>
))
})
5. Modal 컴포넌트 만들기
AlertModal에서는 Modal의 바깥 영역을 클릭하거나 확인 버튼을 눌렀을때 onClose() 함수를 호출한다.
const AlertModal = ({ onClose }:ModalProps) => {
const ref = useRef<HTMLDivElement>(null);
useClickOutside(ref,()=> onClose())
return (
<BaseModal>
<div ref={ref} style={{border:'1px solid #ccc',padding:'30px'}}>
<p>Alert Modal</p>
<button onClick={() => onClose()}>Confirm</button>
</div>
</BaseModal>
);
};
'내일배움캠프' 카테고리의 다른 글
230812 ant design을 쓰면서 느낀 점 (0) | 2023.08.12 |
---|---|
230810 React에서 FullCalendar 기본 사용법 (0) | 2023.08.10 |
230808 useViewport()로 미디어 쿼리 없이 반응형 만들기 (0) | 2023.08.08 |
230807 새로운 프로젝트 시작 (0) | 2023.08.07 |
230806 내일배움캠프 12주차 WIL (0) | 2023.08.06 |