til

최종 프로젝트 13일 차 @드롭 다운, 모달 창 조정 및 css 작업(2) @모달 창 트러블 슈팅

fpzmfks 2024. 11. 5. 22:52

오늘도 어제와 같이 드롭 다운, 모달 창 조정 및 css 작업을 했다. 

 

select태그에 css를 넣기 위해서 아예 드롭 다운으로 select를 만들었고, 오늘도 모달 창 이슈가 있어서 모달 창을 조정했고, 다른 자잘한 css 작업들도 진행했다. 

 

다행히 드롭 다운은 전에 만들어둔 hook을 이용하여 쉽게 구현할 수 있었고, css 작업들도 품이 많이 드는 것 말고는 별 문제 없었지만, 모달 창 이슈가 가장 큰 문제였다. 

 

참가하기 모달 창

이제껏 모달 창을 다룬 경험으로 인해 모달 창의 구조에 대해서 많이 이해하게 되었다. 다만 여전히 모달 창의 오픈 클로저 트리거를 다루는 것이 골치가 아팠는데, 내가 세세한 오픈 클로저 로직을 구현하길 원하는 '참가하기' 모달은 총 3곳에서 사용되며 2가지 방식으로 오픈클로즈를 컨트롤 해야한다. 

 

  1. 모집하기 후 파티를 모집하는 오너가 곧장 파티에 참가하도록 하기(필수적인 과정이므로 닫을 수 없음)
  2. 상세페이지 참가하기초대장 수락에서 파티에 참가하기(모달 창 바깥을 클릭하면 닫을 수 있음)

나는 이 두 가지 경우의 오픈클로즈 트리거를 open 상태값과 openControl 상태값으로 조정했다.

 

open 상태값은 2번에서 일반적인 모달 창처럼 창 바깥을 클릭하면 닫을 수 있고, 참가하기가 종료되면 닫을 수 있도록 한다. 모달 창 컴포넌트 내부에서 선언한 상태값이다. 

 

openControl 상태값은 1번에서 한 번 모달 창이 열리면 참가하기가 성공해서 페이지가 이동될 때까지 닫히지 않는다. 모달창을 사용하는 컴포넌트에서 상태값을 선언해서 props로 내려받은 값이다. 

 

여태껏 이러한 상태값을 통해 모달 창을 다루었지만 콘솔에 찍힌 오류 메세지를 보고 내가 구성한 모달 창 구조로 인해 오류가 뜬다는 것을 알았다. 바로 button 태그를 2중으로 사용했다는 오류였는데, 나는 모달창 컴포넌트로 감싼 button태그를 chlidren props로 내려주고 DialogTrigger 태그가 chlidren을 감싸도록 구성 했다. 

 <DialogTrigger>{chlidren}</DialogTrigger>

 

하지만 DialogTrigger에 버튼 태그가 포함되어 있는 건지 여기에 button 태그를 내려주면 html hydration 오류가 뜨는 것이다.

 

1. button 태그를 div 태그로

나는 이러한 오류를 해결할 가장 간단한 방법으로 button 태그 대신 div 태그 같은 것을 사용하면 될 것이라고 생각했는데, 버튼 태그에만 disabled 값을 줄 수 있기 때문에 이 방법은 실패했다. 이 모달창을 적용해야 하는 곳 중 하나인 모집하기에는 비동기 통신이 포함되어 있기 때문에 그 동안 disabled 값을 줘서 button을 비활성화 시켜야하기 때문이다. 

 

2. 트리거를 따로 만들기

children을 트리거로 감쌀 수 없다면 트리거를 안 보이게 하고 다른 트리거를 만드는 방법을 생각했다. 기존에 openControl을 모달 창을 사용하는 컴포넌트에서 선언해서 받아오는 방법을 선택한 것이다. 

 

트리거를 안 보이게 하는 css

<DialogTrigger className="hidden">참가하기</DialogTrigger>

 

다른 트리거인 openControl을 props로 받아오는 코드

<ParticipationButton
        openControl={open}
        party_id={partyNumber}
        party_situation="모집중"
        isLogin={true}
        setOpenControl={setOpen}
      />

 

하지만 이 방법은 생각만큼 잘 되지는 않았는데, 내가 닫고 싶은 곳에서는 닫히지 않고, 내가 닫고 싶지 않은 곳에서는 닫히는 문제가 일어났기 때문이다. 

 

3. open 상태값을 합치기

open 상태값과 openControl 상태값을 함께 사용하기 때문에 일어난 문제였는데, 아래와 같은 코드였기 때문에 open과 openControl 둘 중 하나라도 true이면 모달 창이 닫히지 않았던 것이다. 이 상황은 setOpenControl로 상태값을 내가 원하는대로 컨트롤 할 수 있으면 해결되는 문제라고 생각했으므로 addEventListner, setTimeout, if문, useEffect 같은 것들을 활용해서 setOpenControl을 사용해보려고 했다. 

<Dialog
        open={open||openControl}
        onOpenChange={setOpen||setOpenControl}
      >

 

그런데 그러다가 onOpenChange에 들어가야 하는 값의 형태가 이상하다는 것을 눈치챘다. 여긴 함수가 들어가야하는 자리이므로 ||를 사용한다고 해도 무엇이든 잘 작동할 리가 없었던 것이다. 때문에 나는 일단 두 open 상태값을 하나로 합치는 작업을 했다. 상태값이 두 개인 것보다 오히려 컨트롤하기가 편할 수도 있을 것이라는 생각이 들기도 했던 것이다. 

 

그렇게 open 상태값을 하나로 합치고 onOpenChange에 값을 배정하다가 아래와 같은 코드를 실험해보자는 생각이 들었다. setOpenControl(true)를 이곳에 넣으면 창이 항상 열린 상태(모집하기에서 사용 시)가 되고, 그냥 setOpenControl을 넣으면 열고 닫는 것이 자유로울 것(그 외에서 사용 시)이라는 생각이 들었던 것이다. 

<Dialog
        open={openControl}
        onOpenChange={() => {
          if (openControl && path.includes('/recruit')) {
            return setOpenControl(true);
          }
          return setOpenControl(!openControl);
        }}
      >

 

다행히 이 코드가 잘 작동을 해서 모집하기에서만 모달 창을 닫을 수 없도록 하는 로직을 완성할 수 있었다. 

 

여러모로 빙 둘러서 해결하긴 했지만 그 과정에서 코드를 잘 살피고 모달 창의 동작을 잘 관찰했기 때문에 얻을 수 있는 해결책이었던 것 같다. 이번 경험이 앞으로의 자신감으로 연결될 것이라고 생각한다.