Front-End/React

[React] Modal toggle 로직 개선 과정

KEMON 2023. 3. 1. 23:04
728x90

리팩터링 책을 읽고 난 후 너무 당연하게 여겨왔던 코드에 대한 의문이 생기는 날이 종종 생겼다.

그 중 하나가 Modal toggle 로직이였다.

어떠한 문제가 있었고 어떻게 개선했는지 예제로 알아보자.

(변수명, 함수명은 예제를 위해 임시로 지어논 이름입니다.)

1. Modal toggle 로직을 변경하고 싶었던 이유

이전의 Modal toggle 로직은 아래와 같았다.

기존 modal toggle

  • 빨간색 박스 : Modal toggle에 관여하는 state 영역
  • 주황색 박스 : Modal toggle 함수
  • 노란색 박스 : Modal을 렌더링 해주는 영역

위와 같은 구조는 Modal이 추가될 때 마다 state를 추가해야하고, state 변화에 따라 toggle 함수를 변경해야 한다. 

또한, 컴포넌트에서 사용되는 state가 많아질수록 Modal에 관여하는 state와 일반 state가 명확히 구분되지 않는다.

 

따라서, Modal 관련 state는 묶고, toggle함수를 최초에 만들어두면 더이상 state의 변화에 따라 toggle함수를 변경하지 않도록 개선하였다.

 

2. Modal 관련 state를 객체로 관리, toggle함수 개선

1차 개선

  • 빨간색 박스 : Modal toggle에 관여하는 state 영역
  • 주황색 박스 : Modal toggle 함수
  • 노란색 박스 : Modal을 렌더링 해주는 영역

state를 객체로 관리함으로써 다른 state와 분리하였으며, 객체의 key 속성을 이용해 toggle 함수가 불변하도록 개선하였다.

이렇게 개선한 와중에 토스 Frontend 진유림님의 클린 코드 관련 유튜브 강연을 보았다.

거기엔 Modal의 toggle 함수가 부모 컴포넌트에서 있을 필요가 없다는 말을 듣고 아차 싶었다.

생각해보면, 주황색 박스의 toggle 함수는 부모 컴포넌트와는 연관되어있지 않은 함수이다.

다른 프론트엔드 개발자분들은 Modal을 어떻게 띄우는가 궁금하였고 custom hook을 통한 Modal 관리 방법을 찾아 적용하였다.

 

3. Custom Hook을 활용하여 Modal 관련 state, toggle 함수 개선

useModal custom hook
custom hook을 활용한 modal 띄우는 방식

  • 빨간색 박스 : Modal toggle에 관여하는 state와 toggle 함수 영역
  • 노란색 박스 : Modal을 렌더링 해주는 영역

이전까지 Modal 관련 state와 toggle 함수를 따로 부모 컴포넌트에서 정의했었지만 custom hook을 통한 useModal을 이용하게되면 주황색 박스 였던 toggle 함수 영역을 따로 지정하지 않아도 된다.

또한, useModal이라는 custom hook 이름으로 다른 state가 많이 정의된다 하더라도 직관적으로 modal 관련 state인지 확인이 가능하다.

 

4. Modal 렌더링 영역에 대한 연구

{openModal1 && <Modal close={toggleModal1} />}

Modal을 렌더링 하는 부분을 보면 부모 컴포넌트의 state와 함께 && 연산자로 묶여져 있다.

이렇게 되면 Modal의 렌더링의 결정을 부모 컴포넌트에서 결정하게 된다.

하지만 Modal을 렌더링 하는 방법은 다른 방식도 있다.

<Modal isShowing={isShowing} close={toggleModal1} />

위와 같이 Modal의 props에 isShowing 변수를 주고 Modal 컴포넌트 내에서 렌더링을 결정하는 방식이다.

Modal의 렌더링 방식을 Modal 컴포넌트 내에서 결정할 수 있게 된다면 더 좋은 코드(더 좋은 관심사 분리)가 되지 않을까? 라는 생각이 들었다.

하지만 이 둘 방식에는 Modal의 close함수를 호출할 때 즉, unmount 시점의 차이점이 존재한다. 

Modal 컴포넌트에 mount 시점과 unmount 시점에 console.log를 찍어 확인해보자.

 

 

1번 Modal은 부모 컴포넌트에서 렌더링을 결정하고 2번 Modal은 Modal Component 내에서 props로 받은 isShowing에 따라 리턴을 하도록 설정하고 console log 를 확인해보면 결과는 다음과 같다.

 

  • 1번 Modal의 경우 open modal 버튼을 클릭해서 모달이 열릴 때 mount, 모달이 닫힐 때 unmount 된다.
  • 2번 Modal의 경우 최초에 부모 컴포넌트가 렌더링 될 때 mount되고 모달이 열리고 닫힐 때에는 mount, unmount 되지 않으며 페이지가 이동될 때 (즉, 부모 컴포넌트가 unmount될 때) 같이 unmoun된다.

따라서 띄우려는 Modal의 특성에 맞게 두가지 방식을 맞게 쓰면 될 것 같다.

 

5. Modal을 부모 컴포넌트 내에서 렌더링하는게 아니라 최상위 혹은 원하는 element에서 렌더링 되도록 하는 방법

여태껏 해온 예제의 Modal component는 부모 컴포넌트의 Modal 컴포넌트 위치에 렌더링 된다.

하지만 ReactDOM.createPortal을 사용한면 부모 컴포넌트 보다 상위 element 혹은 원하는 element 내에서 Modal을 렌더링할 수 있다.

예제를 통해 확인해보다.

modal 부모 컴포넌트
Modal Component
CreatePortalModal

Modal의 경우 일반적으로 사용하던 element를 리턴하는 방식이고 CreatePortalModal은 ReactDOM.createPortal을 이용해 첫번쨰 인자인 element를 두번째 인자인 document.body에 렌더링 되도록 하였다.

위와 같은 구조에서 부모컴포넌트에서 Modal , CreatePoratlModal을 각각 띄운다고 했을 때 Modal이 어디 위치에서 렌더링되는지 확인해보자.

 

  • Modal 컴포넌트의 경우

Modal Component

부모 컴포넌트의 element내에 렌더링된다.

  • ReactDOM.CreatePortal을 이용한 CreatePortalModal의 경우

CreatePortalModal

 document.body 내에 렌더링된다.

 

이 또한 Modal의 성격에 맞게 ReactDOM.createPortal을 적절히 사용하면 좋을 것 같다.

 

728x90