페이지로 만들기는 싫고 간단한 창을 띄워 한 페이지 내에서 유저의 접근을 받고 싶을 때 modal을 애용해 왔다 새 페이지를 왔다 갔다 하는 것보다 좀 더 한 템포 빠르게 유저와의 상호작용이 일어나 좋아했다.
Modal 동작원리
modal을 동작하게 하는 방법에는 크게 2가지가 있다
- modal open close시에 dom에 직접 component를 넣다 빼는 방법
- css의 visible을 이용해서 modal이 안보이는 것처럼 보이게 하는 방법
1번의 방법은 open close마다 component를 랜더링 한다는 의미는 modal전체를 다시 그려야 한다는 것이므로 modal이 커질수록 open close시에 반응이 늦어진다는 이야기이다. 그래서 대부분의 modal창에서는 2번 방법을 사용한다.
Modal의 상태 관리
react에서는 이 modal을 state로 관리한다. 다만 이 modal을 관리하다 보니 고민하나 가 생겼다
//antd 공식문서 예제
import React, { useState } from 'react';
import { Modal, Button } from 'antd';
const App = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const showModal = () => {
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
};
const handleCancel = () => {
setIsModalVisible(false);
};
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal title="Basic Modal" visible={isModalVisible} onOk={handleOk} onCancel={handleCancel}>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Modal>
</>
);
};
ReactDOM.render(<App />, mountNode);
위의 antd 예제처럼 modal을 관리하는 버튼이 있고 밑에 modal component를 넣게 되는데 이 버튼을 클릭 시에 modal창이 열리게 된다.
react는 기본적으로 state가 바뀌게 되면은 컴포넌트가 리 랜더링 되게 된다. modal도 state로 관리를 하기 때문에 open이나 close할때 이 state가 바뀌게 될 것이고 이에따라 해당되는 컴포넌트가 리랜더링 되게 된다.
프로젝트를 하다 보면 버튼이 있는 컴포넌트의 level에서 다양한 tag들이 추가되게 되는데 modal을 관리하는 state가 바뀔 때마다 이들이 전부 리 랜더링이 된다. 또한 하위 페이지에서 modal창을 호출하고 싶으면 props로 하위 페이지까지 넘겨주어야 한다. 이는 컴포넌트의 의존성을 높이게 되는 악영향을 준다.
props시에 문제 상황1
트위터 페이지를 보자
위의 두 개 modal component는 같은 component이다 하지만 위의 props 방법으로 호출하게 되면 메인 페이지와 트윗 댓글 쓰는 페이지에 modal과 state를 두 번 정의해야할것이고 이는 같은 컴포넌트가 두번 랜더링이 되게 되면서 재사용성이 떨어지게 된다.
props시에 문제 상황2
내가 프로젝트에서 경험했던 것이다. modal의 parent component에 mount시에 get요청이 호출되도록 설계를 하였다. modal창을 추가하니 modal 창을 열을 때나 닫을 때 이 parent component가 리 랜더링이 발생하며 get요청이 계속 발생하는 상황에 놓인 것이다.
해결방안
modal의 state를 전역 상태로 바꾸는 것이다 나는 redux를 사용하고 있어서 redux에 새로운 slice를 만든후에 modal을 제어하였다 이렇게 하면 modal이 필요한 어떤 곳에서도 dispatch를 이용해 원하는 modal을 띄울수 있었고 parent component의 rerendering은 일어나질 않는다
//component
<Button type="info" onClick={() => dispatch(openPreviewModal())}>
//클릭시 modal이 열림
//reducer
openPreviewModal: (
state,
) => {
state.previewModal = true;
},
closePreviewModal: (
state,
) => {
state.previewModal = false;
},
- 전역상태로 사용하면 modal을 딱 한 번만 정의하고 모든 페이지 및 컴포넌트에서 이 modal을 사용을 할 수 있다
- 이는 modal과 관련된 리 랜더링을 신경쓰지 않아도 된다.
- modal과 이를 사용하는 컴포넌트간의 의존성이 사라지게 된다.
참고하면 좋은 글
https://www.notion.so/modal-007c2074252b4a4b8ddbe1b1f541f540#5c94fed7f0d5468095100ad42a7cbc71
https://nakta.dev/how-to-manage-modals-1
낙타의 블로그 :: 효율적인 modal 관리 with React(1)
중앙화된 모달 관리
nakta.dev
'구 게시글 > React' 카테고리의 다른 글
JS 프로젝트 TS로 마이그레이션하기 (0) | 2022.11.25 |
---|---|
CSR SSR SSG(NEXT JS) SPA MPA 정리 (0) | 2022.06.19 |
React 상태관리와 불변성 (0) | 2022.05.29 |
SVG 태그 (0) | 2022.05.22 |