Context로 Modal을 함수처럼 사용하는 방법
Toast, Modal을 화면에서 보여줄 일은 서비스를 개발하다 보면 매우 빈번한 일이다.컴포넌트를 공통으로 만들고 해당되는 화면에서 상태값을 추가하고, 컴포넌트를 연결해서 구현하는 과정을 무의
choq.tistory.com
-이 이야기는 위 작업을 한 이후에 발견 및 수정하면서 진행된 이야기 입니다.-

modal을 context로 추가한 이후에 해당 방식이 맘에 들어 toast 메세지까지 추가하는 직업을 진행했다. ModalProvider, ToastProvider 2개의 provider로 나누는 것보다는 하나로 관리하는게 좋을것 같아서 OverlayProvider 를 새로 만들어서 모달과 토스트를 한번에 사용가능하게끔 작업했다. (작명은 토스의 overlay를 참고했다) 그리고 provider 내부에서는 useState 를 가지고 모달과 토스트 값을 각각 관리해주게끔 작업했다.
<OverlayProvider>
.. {children}...
</OverlayProvider>
그렇게 useOverlay 훅 내부에서 showToast, showModal 함수를 사용해서 페이지 단에서 바로 원하는 기능을 구현할 수 있었다. 깔끔하게 상황 종료.
라는 생각이 들 찰라에 리렌더링 이슈가 혹시 있지 않을까 하는 생각이 들었다. children 부모에서 useState 값들이 바뀌게 되면 내부 자식들이 리렌더링 같이 될 수 있기 때문이다. 이 의심이 확신으로 바뀌는데에는 긴 시간이 필요하지 않았다. useOverlay 훅을 사용하는 곳을 찾아서 console.log('rerendering check') 를 추가해두었다. 그리고 해당 화면에서 토스트를 호출했는데 해당 콘솔이 찍혀나오는것을 확인할 수 있었다. 호출 시에 리렌더링이 되고 있었던 것이다. provider쪽 value 를 useMemo로 묶어주는 방식으로 처리해도 리렌더링은 계속해서 발생했다. 그래서 provider에서 역할을 아예 분리시키는 방식으로 목표를 정했다.
export function OverlayProvider({ children }: OverlayProviderProps) {
const portalRef = useRef<OverlayPortalHandle>(null);
const showToast = useCallback(
(message: string | ReactNode, duration = TOAST_DURATION) => {
portalRef.current?.showToast(message, duration);
},
[],
);
const showModal = useCallback((options: ShowModalOptions) => {
portalRef.current?.showModal(options);
}, []);
const closeModal = useCallback(() => {
portalRef.current?.closeModal();
}, []);
const overlayValue = useMemo(
() => ({
showToast,
showModal,
closeModal,
}),
[showToast, showModal, closeModal],
);
return (
<OverlayContext.Provider value={overlayValue}>
{children}
{createPortal(<OverlayPortalLayer ref={portalRef} />, document.body)}
</OverlayContext.Provider>
);
}
ref를 이용해서 프로바이더 자체는 아래 <OverlayPortalLayer /> 쪽 일을 시키는 업무를 전담하게 했고 상태값 관리는 아예 배제시켰다. <OverlayPortalLayer /> 컴포넌트 쪽에서 useState 이용해서 값을 변경하는 방식으로 진행했다. 그래서 값이 바뀌어서 리렌더링 되더라도 다른 부분에 영향 없이 해당 컴포넌트 자식들만 리렌더가 되게끔 했다. 이렇게 수정하고 나서는 토스트나 모달을 호출해도 해당 페이지에서 리렌링이 발생하지 않았다..!! (토스트를 호출해도 console.log 가 찍히지 않음)
토스트 메세지 호출을 단순화 하기 위해서 시작했던 작업이었는데
리렌더링 관련한 문제까지 직면하면서 일이 커진 느낌이었지만..
결국 손쉬운 호출과 리렌더링 이슈 모두 잡았으니 해피엔딩인것으로..
'Front-end' 카테고리의 다른 글
| ponytail 적용하면 얼마나 달라질까? (4) | 2026.06.24 |
|---|---|
| [FE] safari에서 sticky 이슈 in <table> (0) | 2026.06.10 |
| 한글 번역 막기 (0) | 2026.04.20 |
| Context로 Modal을 함수처럼 사용하는 방법 (3) | 2026.04.17 |
| error Cannot read properties of null (reading 'edgesOut') 빌드 오류 해결하기 (0) | 2026.04.14 |