파편화된 모달 관리를 효율적으로 한 곳에서 함으로써 해결 (중앙화된 모달관리)
1. 기존 프로젝트에서의 모달의 문제2. 중앙 관리를 통하여 모달 문제 해결하기1.모달을 열고 닫는 상태는 ContextAPI를 통해 전역으로 관리한다.2. 모든 모달에 공통적으로 적용할 부분과 각 컴포넌트의 비즈니스 로직 처리를 구분한다.3. 모달 컴포넌트 중앙에서 관리하기3. 정리
1. 기존 프로젝트에서의 모달의 문제
- 모달 사용 부분
모달 컴포넌트
[문제점]
- 모달 사용 부에서 모달 상태를 관리하기 위한 부수적인 코드가 많아진다.
- 모달을 이용하는 모든 컴포넌트에서, 해당 컴포넌트의 로직과 모달 사용 로직이 같이 존재하여, 가독성이 떨어지게 된다.
- 하나의 목적의 코드가 물리적으로 흩뿌려져 있다.
모달의 상태관리 부
, 모달을 여는트리거 컴포넌트
, 가장 하단 부에 자리 잡은Modal컴포넌트
- 모달에서 어떤 일이 일어나는지 알 수 없다.
- 모달은 컴포넌트 기본 특성으로 열고 닫힘에 따라 특정 동작을 갖는다. 하지만 현재 구조에서는 해당 모달이 열고, 닫을 때 어떤 동작을 하는지 알 수 없기 때문에 모달의 역할을 파악하는 것도 어렵다.
- 확장성이 부족한 모달 컴포넌트 설계
- 여러개의 모달이 필요한 경우 대응하기 어렵다.
- 현재 모달의 경우, 취소 및 확인 에 대한 비즈니스 로직에 대응하기 어렵다.
2. 중앙 관리를 통하여 모달 문제 해결하기
[해결방법]
모달을 열고 닫는 상태와 비즈니스 로직 처리를 위한 코드를 분리해낸다.
1.모달을 열고 닫는 상태는 ContextAPI를 통해 전역으로 관리한다.
효과
modal을 열고 닫기 위한 불필요한 props 제거
효과
여러개의 모달을 사용하더라도 중복된 코드가 발생하지 않는다 (상태관리 직접하지 않기 때문에)
How
1) 현재 열려져 있는 모달 상태와 이를 dispatch 하는 함수를 Context API를 통한 전역상태로 관리ModalStateContext
는 현재 렌더링해야할 모달들을 관리하는 상태이다.- 모달 컴포넌트와 해당 모달에서 사용할 props를 가지는 형태로 저장한다.
- 이를 통해 여러 개의 모달을 여는 상황에 대해 대처가 가능하다.
ModalDispatchContext
는 ModalState에 대한 Action 함수들을 정의한다.- 모달의 기본 핵심 로직인 open과 close에 따라 모달을 열고 닫는 action을 정의한다.
참고
: 두 개의 Context로 분리하는 것은 useModal Hook에서 dispatch Context만을 사용하여, hook을 사용하는 컴포넌트에서 리렌더링이 일어나는 이슈를 방지하기 위함ModalProvider
를 전역에 등록함으로 어디에서나 모달을 열고 닫을 수 있도록 한다.
[ModalContext]
[ModalProvider]
차이 확인하기
- 어떤 이벤트로 모달이 열리고, 모달이 어떤 역할을 하는지 직관적으로 파악할 수 없는 문제
- 코드의 응집도가 높아지고, 선언적으로 작성하여 코드의 가독성을 높임
1) 로그인 버튼을 누르면, 2)
LoginModal
컴포넌트가 열리고, 3) LoginModal
을 제출하면 log함수가 실행
되는 것을 직관적으로 알 수 있게 되었다.before
after
2. 모든 모달에 공통적으로 적용할 부분과 각 컴포넌트의 비즈니스 로직 처리를 구분한다.
효과
공통 모달 로직을 정의하여 편리성을 확보하고, 비즈니스 로직을 분리할 수 있어 유지보수에 유리하다.
How
1) 공통 모달 로직은 Modal을 렌더링하는 부분에서 정의하여, 각 모달 컴포넌트의 props로 내려준다.- 모달은 대부분 확인/취소의 두가지 동작이 존재하기 때문에, 모든 모달 컴포넌트 내부에서 각각 등록하지 않고, 정의된 함수를 prop으로 받아 사용할 수 있도록 구현한다.
handleSubmit
은 props로 받은 onSubmit(모달 고유의 제출 로직)을 실행한 직후, 모달을 닫게 해주는 util 함수라고 할 수 있다.- 그 외 다른 비즈니스로직을 위해 필요한 Props는 restProps 형태로 내려주게 된다.
추가
- onSubmit() 함수가 매개변수를 필요로 한다면, Modals에서 공통으로 처리하는 것이 아닌, 각 모달 컴포넌트 단에서 인자를 넘겨줄 수 있도록 한다.
3. 모달 컴포넌트 중앙에서 관리하기
현재 프로젝트에서는 모달이 많지 않지만, 모달의 수가 많아지고 복잡해진다면, 초기 렌더링 시 모든 모달 컴포넌트를 import 하게 되어 초기 로딩 속도에 영향을 줄 수 있다. 따라서 모든 모달을 한 곳에서 관리하고 lazy로딩 처리를 하고자 한다.
효과
Lazy로딩을 통해 모달이 실제로 사용되는 순간에 import 되어 초기 로딩 속도 향상을 가져온다.
how1
사용되는 모든 모달 컴포넌트를 객체(이름:component)로 매핑하고, 사용부분에서는 컴포넌트가 아닌 이름을 통해 불러온다.
how2
하나의 모달이 불러와 질 때, 모든 모달이 한 번에 로딩되는 것을 방지하기 위해 dynamin import 기법을 적용한다. (React.lazy 이용)
결과 확인
- 최초 로딩 시, Modal 컴포넌트는 로드 되지 않는다.
- 로그인 모달을 열었을 때, LoginModal 모듈만이 로드된다.


3. 정리
기존 프로젝트에서 Modal은 아래와 같은 문제를 가지고 있었다.
1) 사용 컴포넌트의 내부에서 모달상태를 관리하는 문제
2) 사용 컴포넌트 내부에서 모달 트리거와 모달컴포넌트의 응집도(물리적거리)가 떨어져 있는 문제
3) 모달의 기본 동작(
확인/취소
)에 대한 공통 로직 처리와 사용 컴포넌트에서 비즈니스 로직을 연관하여 처리할 수 없다는 문제추가로 모달의 수가 많아지는 경우의 성능저하 문제를 전혀 고려하고 있지 않았다.
개선된 Modal 에서는
1) 파편화 되었던 모달 컴포넌트들을 ContextAPI와 Modals 컴포넌트를 통해 중앙 관리할 수 있게 되었다.
- 이를 통해 컴포넌트 내부에서 모달상태를 신경쓰지 않게 되었다.
2) useModal hooks를 만들고, openModal이라는 함수로 모달 관련 코드를 응집시킬 수 있었다.
- 모달을 여는 트리거 컴포넌트 모달 컴포넌트의 역할을 직관적으로 알 수 있게 되었다.
3) Modals를 렌더링하여 줄 때, 공통적인 동작에 대한 함수를 props로 내려줌으로써 모달을 열고닫는 처리를 각각의 모달 컴포넌트가 신경쓰지 않는다.
- 중복된 기능에 대한 코드를 줄일 수 있었다.
4) LazyLoding을 적용하기 위해 dynamin import 기법을 적용하였고, 이를 통해 많은 모달이 있을 경우의 성능문제에 대비하였다.
- 모달의 사용량이 많아지는 상황에 대한 최적화와 확장성을 가지게 되었다.