useModal - 여러 개의 Modal을 선언적으로 관리하는 방법론

Yoonkeee·2024년 1월 27일
117

토스 오더

목록 보기
2/2
post-thumbnail

(2) - useModal, 여러 개의 Modal을 선언적으로 관리하는 방법론

이 글에서는 여러 개의 Modal을 Stateful하고, 선언적으로 사용할 수 있는 방법론을 제시해요.

토스 오더 프로젝트는 여러 개의 Modal을 적극적으로 사용하였어요.
토스 오더 - 가장 쉬운 테이블 오더 (1) - 직관적인 UI/UX를 어떻게 만들었나요?

  1. 사용자의 인식과 의식을 고려했어요.
    페이지의 이동이 발생하거나, Layout이 크게 변하면 사용자는 페이지에 대해 처음부터 다시 파악해야 해요. 이 문제를 해결하기 위해 Page Depth를 없애고, Modal을 적극적으로 활용했어요.

개요

  • 서론에서는 기본적인 Modal에 대한 설명과 사용 방식을 볼 수 있어요.
  • 본론에서는 custom hook을 사용한 선언적인 Modal 사용 방식을 제시해요.
  • 결론에서는 본 프로젝트에서 어떻게 적용하였는지 볼 수 있어요.

서론

Modal이란?

사용자의 이목을 끌기 위해 새로운 window 창이 나타나서, 사용자의 행동을 요구하거나 중요한 데이터를 표시해요.
브라우저의 요소로 동작하는 Alert 또는 Popup과 다른 점은 브라우저의 viewport 안에 나타나는 DOM 요소라는 점이에요.
즉, UI의 일부에요.

Modal의 장점과 단점

장점

  1. 사용자의 이목을 집중시킬 수 있어요.
  2. 사용자의 액션을 강제로 요구하기 때문에 핵심 BM을 담아내기에 적합해요.
  3. 새로운 페이지로 이동하는 것보다 파악이 빨라요.

단점

  1. Modal이 열려있을 때에는 기존 페이지의 Interaction을 block하기 때문에 남발해서는 안돼요.
  2. BM 혹은 사용자의 의도와 관련이 적은 Modal은 사용자에게 불편함과 귀찮음을 줄 수 있어요.
  3. Modal에는 많은 양의 데이터를 담는 것은 곤란해요. 장점 1과 3을 다시 생각해본다면, 많은 데이터를 담아야 한다면 새로운 페이지로 설계하는 것이 더 나은 방향일 거에요.

기본적인 Modal 사용법

Chakra UI의 Modal 사용법은 아래와 같아요.

좀 복잡하죠. 의도를 가볍게 표현하는 코드로 제가 다시 작성해볼게요.

위 함수형 컴포넌트(이하 컴포넌트)인 <Modal버튼컴포넌트>에는 클릭하여 <Modal>을 열기 위한 <버튼>이 있고, 그에 해당하는 <Modal>이 있어요.

<Modal>에 대한 <버튼>을 어떻게 사용하면 될까요?

위 코드처럼 필요한 곳에서 <Modal버튼컴포넌트>를 불러와서 사용할 수 있어요.

버튼을 클릭하면 Modal이 열릴 것 같아요.

하지만 이러한 구조의 문제는 무엇일까요?

기존 사용법의 문제점

<Modal>이 실행되면 console.log를 실행하도록 해볼게요.

열기 버튼을 누르기 전까진 <Modal>이 렌더되지 않으니까, <Modal>이 열리기 전까진 console.log의 내용도 보이지 않을 것 같아요.

어? 아직 <Modal>을 열지 않았는데, 안에 있는 console.log가 벌써 실행되었어요.
만약 이 <Modal>의 내용이 중요한 연산을 수행하거나, API 호출이 발생한다면 이대로는 안될 것 같아요.
<Modal>이 보여지기 전까진 <Modal>이 실행되지 않도록 해볼까요?

<버튼>을 클릭하여 isOpentrue일 때만 <Modal>이 실행되도록 수정해봤어요.

<Modal>이 열리기 전까진 console.log가 실행되지 않네요.

좋아요. 기대했던 대로 작동하고 있어요. 그런데, 이 코드는 나쁜 코드에요.

  1. 선언적이지 않으며,
  2. <버튼><Modal>의 결합이 강해요.

즉, <Modal>이 자신을 열어주는 버튼 혹은 그 액션에 종속되어있어요.

이 문제를 개선하기 위해 useModal이라는 custom hook을 만들어볼게요.

원하는 바는 세가지에요.

  1. <Modal>을 열어주는 Action에 <Modal>이 종속되지 않았으면 좋겠어요.
  2. 선언적인 코드를 원해요.
  3. 당연히 <Modal>이 열리기 전까진 실행되지 않아야 해요.

본론

기존의 코드 개선하기

1. Modal을 열어주는 Action에 <Modal>이 종속되지 않았으면 좋겠어요.

지금까지 작성한 코드를 다시 살펴볼까요?

하나의 <Modal버튼컴포넌트> 내에서 Modal의 열린 상태(isOpen)를 boolean으로 갖고 있고, 이 상태를 제어하는 action이 <Modal> 바깥의 <버튼>에 담겨있어요.

이 둘의 관계를 끊고 싶어요. 그러려면 isOpen의 상태와, 이를 제어하는 action을 분리하면 될 것 같아요.
Context API 혹은 전역 상태 관리로 따로 빼주면 좋을 것 같아요.
저는 Recoil을 사용해서 구현해볼게요. <Modal><버튼>도 3개 정도 만들어 볼까요?
회원 가입을 하는 상황이라고 가정해보고, 일반적인 회원 가입과 깃헙, 구글의 계정으로 회원가입도 가능하다고 해볼게요.

<Modal>isOpen boolean값을 Recoil을 이용해 전역 상태로 관리해볼게요.

그리고 이 상태를 불러오고, 열거나 닫는 action을 갖고올 수 있는 hook, useModal을 구현해볼게요.

useModal

useModal에 대상이 되는 Modal의 이름을 넣으면 이에 대한 isOpen 상태 혹은 이를 컨트롤하는 action을 받아올 수 있도록 했어요.
버튼에는 useModalonOpen을 받아오고, Modal에서는 isOpenonClose를 받아오면 될 것 같아요.

개선된 버튼

<버튼> 자체에서 onClick에 대한 action을 useModal로부터 직접 불러와서 할당했어요.

개선된 Modal

<회원가입Modal> 하나만 살펴볼게요.
Modal 자체에서 필요한 isOpenonCloseuseModal로부터 직접 불러와서 할당했어요.
이제 페이지 컴포넌트는 어떻게 수정할 수 있을까요?

2. 선언적인 코드를 원해요.

<버튼 컴포넌트><Modal 컴포넌트>가 분리되었어요.
각 컴포넌트가 Stateful하므로 페이지는 isOpen에 대한 상태나 action을 알 필요가 없어졌어요.
결과물을 한번 볼까요?

useModal hook을 사용하였기 때문에 각 Modal들과 버튼들을 선언적으로 넣어주기만 해도 되네요!

3. 당연히 <Modal>이 열리기 전까진 실행되지 않아야 해요.

앗! 하지만 다시 Modal이 열리기 전에 실행되기 시작했어요.
그리고 지금의 형태로는 Modal이 많아질 수록 <페이지 컴포넌트>의 코드가 복잡해질 것 같아요.
개선해볼까요?

전역 상태인 modalStore에서 어떤 상태가 true로 변경된다면, 그 Modal을 렌더할 수 있게 반환해주는 <Switch>라는 컴포넌트를 만들었어요.

이제 <Modals> 컴포넌트에서 각 Modal들을 불러와 <Switch>에 넣어줄게요.

여러 개의 Modal을 하나의 컴포넌트로 줄일 수 있게 되었어요.
물론 전역 상태를 사용하기 때문에, 다른 페이지나 자식 컴포넌트에서도 당연히 Modal을 열 수 있어요.
3번의 조건을 충족하는지 다시 볼까요?

좋아요. 초반에 의도했던 대로 Modal이 열리기 전까진 실행되지 않네요!
이렇게 전역 상태를 이용하여 Modal의 사용 방식에 대한 고민을 해결했어요.

결론

토스 오더에 적용한 결과

page.tsx

modals.tsx

앱의 <Page><Modals>만을 넣어 선언적인 코드 작성을 이루어냈어요!
이제 다양한 종류의 Modal을 쉽게 사용할 수 있게 되었어요. 토스 오더에는 어떤 Modal들이 있는지 볼까요?

잘못되었거나 부족한 부분이 있다면 자유롭게 피드백 해주세요!
코드에 대한 이야기를 하는 것을 좋아해요.
긴 글 읽어주셔서 감사해요!😚

Deployed Product
Github Repository

10개의 댓글

comment-user-thumbnail
2024년 1월 27일

chakra ui의 useDisclosure를 간단히 만드셨군요! 좋은 글 감사합니다~!

답글 달기
comment-user-thumbnail
2024년 1월 28일

짱개발자~

답글 달기
comment-user-thumbnail
2024년 1월 31일

백엔드 개발자로서 생소한 부분이 많을 수도 있는데, 절마다 두괄식 표현과 함께 간단명료한 설명으로 수월하게 잘 읽었습니다!

답글 달기
comment-user-thumbnail
2024년 2월 1일

모달 컴포넌트를 만들기까지의 많은 고민들이 느껴져서 좋았습니다~!

답글 달기
comment-user-thumbnail
2024년 2월 5일

confirm 모달과 같이 사용자 입력에 따라 로직이 달라지는 모달의 경우 콜백 함수를 recoil로 전달하여 구현하신건가요??

1개의 답글
comment-user-thumbnail
2024년 6월 19일

저도 UIUX 디자인이하고 싶어서 이것저것 찾아보는 중인데, 귀한 정보 알려주셔서 정말 감사합니다ㅠㅠ 이 글 보니까 저도 얼른 준비해서 UIUX 디자인 해보고 싶어요ㅜㅜ 그런데 요즘은 UIUX 디자인 준비할 때 부트캠프 많이 한다고 하던데.. 현직자가 붙어서 실무 경험 쌓게 해주고, 포트폴리오 만들 수 있다고 해서 혹하네요. 제가 찾아본 곳은 여기있는데 (수강생들이 만든 포폴 보니까 혹해서요..) 주 3일만 들어도 UIUX 디자이너로 취업할 수 있는거 같더라고요. 혹시 여기는 어떻게 보시나요?
https://zrr.kr/kaZT

답글 달기