뒤로가기 대신 모달 닫기

cjkangme·2023년 12월 19일
0

react

목록 보기
6/6

간단한 react app을 만들어 보았다.

홈 화면에서 버튼을 누르면 어딘가로 이동하고,
어딘가에서 버튼을 누르면 요상한 내용의 모달을 띄운다.

마우스로 조작하는 PC에서는 이런 모달창에서 대부분 마우스를 움직여 '취소'를 누르겠지만.

모바일 환경에서는 '뒤로가기 버튼' 또는 '뒤로가기 제스처'를 사용하는 것에 익숙하기 때문에 취소 버튼을 누르는 대신에 뒤로가기를 하게될 수 있다.

그런데 뒤로가기를 누르면 모달이 닫히는게 아니라 페이지가 뒤로 가버린다.
모달을 여는 것은 페이지를 이동할 때 처럼 브라우저의 history 객체에 스택을 쌓는것이 아니기 때문이다.

그렇다면 모달이 띄워져있는 상태에서 뒤로가기를 했을 때,
페이지를 이동하는 것이 아니라 모달만 닫고 싶다면 어떻게할까?

searchParams (쿼리 스트링)

MDN - URL: searchParams property

searchParams는 URL Web API가 제공하는 인터페이스로, GET 요청을 할 때 사용하는 쿼리 스트링을 다룰 때 사용한다.

https://search.naver.com/search.naver?query=nureongi0214

위 링크에서 query=nureongi0214가 바로 쿼리스트링에 해당한다.
URL에서는 ? 기호로 쿼리 스트링의 사용 시작을 알리고, & 기호로 각 파라미터를 구분한다.

searchParams 인터페이스를 사용하면 params.get("query"); 형태로 nureongi0214라는 값을 얻을 수 있다.

searchParams는 라우트 경로에 영향을 주지 않으므로, 같은 페이지에서 searchParams만 바꾸면 마치 상태 변수처럼 현재 페이지에 표시할 정보를 바꿔줄 수 있다.

useSearchParams

react-route-dom이 제공하는 훅으로, 앞서 설명한 searchParams 인터페이스처럼 현재 경로의 쿼리 스트링을 다룰 수 있다.

useSearchParams의 특별한 점은 바로 setSearchParams 함수를 제공하여 useState훅과 같이 searchParams를 상태처럼 사용할 수 있다는 것이다.

import { useSearchParams } from "react-router-dom";

const Test = () => {
  const [searchParams, setSearchParams] = useSearchParams();

  return (
    <Wrapper>
      <h1>어딘가</h1>
      <div>현재 SearchParams</div>
      <ul>
        {[...searchParams.values()].map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <button
        onClick={() => {
          // setShowModal(true);
          setSearchParams({ hello: "world" });
        }}
      >
        버튼
      </button>
      
      {/* ... */}
  )
}

위와 같이 setSearchParams 함수에 key-value 형태의 인자를 전달하면 url에 쿼리 스트링을 추가해준다.

또한 useState로 상태를 관리할 때 처럼 변경된 쿼리 스트링을 반영하여 리렌더링 한다.

한가지 더 특별한 점은 setSearchParams 함수는 navigate 처럼 동작하여 리액트 앱이 관리하는 history 객체에 스택을 쌓아준다는 것이다.

이를 활용해 모달을 열고 닫을수도 있다.

useSearchParams로 모달 여닫기

import { useSearchParams, useNavigate } from "react-router-dom";

const Test = () => {
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();

  return (
    <Wrapper>
      <h1>어딘가</h1>
      <button
        onClick={() => {
          setSearchParams({ showModal: "true" });
        }}
      >
        버튼
      </button>

      {searchParams.get("showModal") && (
        <ConfirmModal
          content="저에게 1억을 주시겠습니까?"
          description="주고 싶다면 확인을 눌러주세요"
          onCancel={() => {
            navigate(-1);
          }}
        />
      )}
    </Wrapper>
  );
};

export default Test;

위와 같이 searchParams에서 모달을 열고 닫는 키(showModal)를 조회하여 모달의 표시 여부를 결정하면 된다.

또한 취소 버튼을 누를 때 동작으로 뒤로가기 동작(navigate(-1))을 취하도록 해주면
취소 버튼, 뒤로가기 동작으로 모달을 닫을 수 있게 된다.

이제 모바일에서도 어색하지 않게 동작하는 모달을 만들어 냈다.

사실 뒤로가기를 방지하는 방법은 이 방법 말고도 더 있지만

이 방법이 여러 모달을 중첩시키거나, searchParams.get("showModal")로 얻는 값을 렌더링에 사용하는 등 여러가지 방법으로 활용할 수 있는 좋은 방법인 것 같아 이번 프로젝트에서 사용하고 있다.

혹시나 비슷한 문제로 고민하고 있는 사람이 있다면 이 방법이 조금이라도 도움이 되길 바란다...

0개의 댓글