React Router6 조회 조건과 결과를 history에 남기고 싶다.

9/4/2024


react router 뿐만 아니라 react를 사용하면서 조회 화면을 만들면 비동기로 fetch한 조회 결과나, 조회를 위한 조회 조건을 유지할 수 없는 문제가 있다.
예를 들면 페이지나 컴포넌트의 이동이 일어났을 때, 이전 페이지(컴포넌트)로 돌아가면 이전에 조회했던 내용이 전부 사라지고 초기화 된다.
이는 사용자에게 큰 불편함을 줄 수도 있는데, 목록 조회 페이지와 상세 페이지를 오가는 과정에서 목록 조회 페이지가 계속 초기화 된다면 매번 조회 조건을 설정하고 조회 버튼을 클릭 해주어야 하는 상황이 된다.
이를 방지하기 위해 페이지(컴포넌트)의 이동 직전에 마지막 상태를 저장해줄 필요가 있다.

React Router6를 사용한다고 가정하고 서술해본다.
React Router는 6부터 history 관련 객체 및 hook이 없어졌다. 대신 관련 기능들이 locaiton과 navigate로 옮겨갔는데,
본 문서에서 다룰 중요한 hook들은 useLocation, useNavigate, useSearchParams이다.

useSearchParams (조회 조건 저장)

먼저 살펴볼 것은 useSearchParams hook이다.
해당 hook은 이름에도 나와 있듯 search param을 손쉽게 관리해주는 hook이다.
(설마 모르는 이를 위해 설명하자면 search param은 url에 명시되는 query string이다 "?param1=222&param2=333" 이러한 형식)

const [searchParams, setSearchParams] = useSearchParams();

searchParamsURLSearchParams가 주어진다.
searchParams를 수정하려면 setSearchParams를 호출하면 되는데, 간단하게 객체 형태를 넣어주면 된다.

setSearchParams({
   key1 : value1,
   key2 : value2
})

이렇게 설정하면 자동으로 url에 ?key1=value1&key2=value2가 붙게된다.
주의할 점은 setSearchParamsnavigate와 동일하게 동작한다는 점이다. 즉, setSearchParamssearchParams를 변경하면 url만 바뀌는 것이 아니라, 실제로 페이지의 이동처럼 처리된다는 것이다.
실제로 setSearchParams만 호출해도 history에는 새로운 페이지가 push된다.
그렇기 때문에 setSearchParams에는 두 번째 인자로 navigate와 동일한 옵션 인자를 받는다. 만약 history에 push되지 않고 현재 페이지의 history를 덮어쓰고자 한다면 replace 옵션에 true를 주자.
자, 그렇다면 이제 이 useSearchParams hook을 어떻게 사용할 것이냐. 간단하다. 조회 조건의 값들이 변경될 때 마다 searchParams를 변경해주면 된다.
그러면 url에는 현재의 조회 조건들이 기록되어 남게되고, 새로고침이나 뒤로가기 등으로 다시 조회 페이지로 돌아오더라도 searchParams를 통해 이전의 조회 조건들을 불러올 수 있게 된다.

useNavigate (페이지 이동 및 상태 전달)

react router를 사용한다면 useNavigate hook은 익숙하게 사용할 것이다.
useNavigate는 페이지를 이동하기 위해 사용하는 대표적인 hook인데, 첫 번째 인자로는 이동할 페이지의 라우터 path를 받고, 두 번째 인자로는 옵션 인자를 받는다.
옵션 인자에는 여러가지가 있는데, 본 문서에서 다루고자 하는 것은 state 옵션이다.
state 옵션은 이동한 페이지로 데이터를 전달하기 위한 방법으로 사용되는 옵션이다. useNavigate hook에 전달된 state는 이동된 페이지에서 location을 통해 접근할 수 있다.
그렇다면 state 옵션에 어떤 데이터를 전달해야 할까. 보통 이러한 방식을 사용하는 상황은 목록 조회 화면에서 상세 화면으로 이동할 때 나타난다.
즉, 상세 화면에서 다시 목록 화면으로 돌아갈 때 필요한 정보들을 state로 전달해 주고 상세 화면에서 목록화면으로 돌아갈 땐 전달된 state를 활용하여 돌아오도록 구현하는 것이다.
목록 화면에서 상세 화면으로 이동할 때 전달할 state에는 조회 조건, 현재 조회된 목록 데이터 등이 있을 수 있다.
그리고 상세 화면에서 목록 화면으로 돌아갈 때 다시 그 state를 전달함으로써 이전 목록 화면에서 과거의 목록 화면 상태를 유지할 수 있는 것이다.

그런데 상세 화면에서 목록 화면으로 돌아가는 것이 아니라 목록 화면에서 조회 후 다른 페이지를 갔다가 브라우저의 뒤로가기 기능을 이용해 다시 목록 화면으로 돌아올 경우엔 어떻게 될까?
위에서 서술한 방식은 상세 화면에서 특정 버튼을 통해, 즉 동일한 생애주기 안에서 이루어지는 컴포넌트간 이동에 적용되는 방식이다.
브라우저를 통해 새로고침을 하거나 뒤로가기를 통한 페이지 이동은 생애주기가 연결되지 않고 컴포넌트간 이동이 아니다.
따라서 별도의 처리가 필요한데, 본 필자는 이를 해결하기 위한 방법으로 목록을 조회할 때 마다 조회된 현재의 상태를 state에 저장하여 history를 replace하는 navigate를 활용했다.
즉, 사용자는 느끼지 못하겠지만 조회 버튼을 클릭할 때 마다 history는 매 번 새롭게 교체되는 것이다.
이렇게 교체된 history에는 마지막으로 조회한 조회 결과 데이터 및 조회 조건들이 담겨져 있으니, 이제 브라우저에서 뒤로가기를 하여도 이전의 state를 유지할 수 있게 된다.

useLocation (state 값 접근)

이제 마지막으로 useNavigate hook으로 전달된 state를 활용하기 위한 useLocation hook이다.
목록 조회 페이지에서는 useEffect로 페이지 컴포넌트가 마운트 될 때, useLocation으로 state에 접근하여 존재하는 state에 따라 조회 조건과 조회 결과를 초기에 설정해줄 수 있다.
결국 본 문서에서의 핵심은 바로 이 useLocation이 되는 것이다.
useLocation에 담긴 stateuseNavigate로 인해 전달된 값이 될 수도 있고, replace된 history에 담겨있는 값이 될 수도 있다.
따라서 이를 사용하는 페이지(컴포넌트)에서는 어디서 담겨온 것이든 useLocationstate를 통해 초기 상태를 이전의 상태로 설정할 수 있는 것이다.

develop

Inhyeok Kim

Email : inhyeok.kim@icloud.com

GithubPortfolio