Next.js 에서 페이지 검색 결과 URL로 유지하기 (feat. window.location.search)

seung·2024년 5월 22일
0
post-thumbnail

Next.js 에서 페이지 검색 결과 URL로 유지하기

생성일: 2023년 11월 6일 오후 2:32

페이지 URL 내 검색 결과 기억하기?


이번 스프린트에서 커머스 개선점 처리 목록에 뒤로 가기 시 이전 페이지 URL 기억하고 해당 URL 로 돌리기 라는 QA(?)가 있었습니다.

이건 이전부터 계속 고민했었던 부분이기도 했습니다. 🤔

검색 및 필터 조건이 걸린 페이지의 링크를 그대로 복사해 접속하면 그대로 그 검색결과가 유지된 상태를 보여주고 싶었습니다.

예를 들면 네이버로 검색어는 강아지, 검색 타입은 이미지를 설정해 검색해보겠습니다.

강아지의 이미지 검색결과가 나오고 해당 링크를 복사해서 다른 사람에게 공유해보면 다른 사람들도 동일한 강아지의 이미지 검색 결과를 볼 수 있습니다.

강아지 : 네이버 이미지검색

뒤로 가기 시 이전 페이지의 링크를 기억하고 동일한 검색 결과를 보여준다는 건 해당 링크의 검색 결과를 유지하고 보여주는 것과 동일한 원리이고 하나의 기능을 적용하면 모두 해결될 거라고 생각했습니다.

그래서 어떻게 검색조건을 유지할 것인가를 찾아보니 거의 대부분의 사이트에서는 URL 의 파라미터에 검색 조건을 저장하고 있었습니다.

저희 회사에서 운영중인 큐샵의 admin 페이지는 Next.js 를 사용하고 있으니 router.push 라는 기능을 이용하여 파라미터에 검색 조건을 추가해보기로 합니다!


실제 프로젝트에 반영해보기


제가 생각했던 로직은 아래와 같았습니다.

일단, URL 에 검색 조건을 지정해서 이동시키고 난 후 파라미터 값을 가져옵니다.

그리고 가져온 파라미터 값으로 검색 조건을 지정해서 다시 검색합니다.

검색 시 URL 파라미터에 검색 조건 지정파라미터 값 가져옴가져온 파라미터 값으로 검색


검색 조건들 status 선언

이제 이 로직대로 판매의 반품관리 페이지에 적용을 한 번 진행해보겠습니다.

해당 페이지에서 필요로 하는 검색 조건은 page(페이지), count(페이지 당 개수), status(반품상태) 3가지입니다.

일단, 각 조건을 status 로 선언을 해주었습니다.

page 의 기본값은 1, count 기본값이 10, status 는 기본값 requested 입니다.

const [page, setPage] = useState(1)
const [count, setCount] = useState(10)
const [status, setStatus] = useState('requested')

그리고 해당 프로젝트는 서버 데이터를 호출하기 위해 react query 를 사용하고 있었기 때문에 각 검색 조건들이 변경될 때 마다 API 를 호출해올 수 있도록 쿼리키로 지정해주었습니다.

(react query 에 대한 설명은 따로 하지 않겠습니다.)


// getOrderReturn 은 반품 목록 API 호출 함수
const { data: returnList, isFetching } = useQuery(['orderReturnList', page, count, status], () => {
  return getOrderReturn({ page, count, status: [status] })
})

이렇게 까지만 해주면 해당 페이지 처음 접근했을 때 각 기본값이 적용된 데이터들을 가져옵니다.


URL 에 파라미터 추가

다음으로 해야하는건 검색 조건이 변경될 때마다 URL 의 파라미터에 검색 조건을 추가하는 것입니다.

반품관리 화면에서는 상단에 있는 상태를 클릭하면 각 상태로 데이터를 필터링하는 기능이 필요했습니다.

아래와 같이 상단 상태바를 클릭하면 **router.push 를 이용하여 query 와 함께 페이지를 이동시키는 로직을 추가**했습니다.

router.pathname 으로 현재 URL 경로를 가져오고, 옵션 객체의 query 에 필요한 검색 조건들을 입력합니다.

새로운 상태값의 결과를 보여줘야 하므로 page는 1 페이지를, count는 이전에 설정한 값 그대로, status는 내가 클릭한 상태값을 넣어줍니다.

<StatusBox
	...
  onClick={() => {
		**router.push(router.pathname, { query: { page: 1, count, status: 선택한상태값 } })**
  }}
>
...
</StatusBox>

이렇게 까지하면 URL 에 지정한 query 를 포함한 링크로 이동되는 것을 볼 수 있습니다.

ex. /admin/order/refund?page=1&count=10&status=requested


가져온 파라미터 데이터로 검색

그런데 자세히 보면 URL만 변경이 되고 데이터 목록은 처음 불러왔던 데이터 그대로 검색이 되지 않고 있습니다.

지금은 단순히 URL만 변경한 것이므로 파라미터를 가져와 해당 검색 조건으로 다시 API 를 호출해야 합니다.


💩 router query 로 파라미터 가져오기 실패

처음엔 URL의 파라미터는 router.query 를 이용해 router.push 로 페이지가 이동될 때 useEffect 로 router 를 감지하여 값을 가져오면 되겠거니 했습니다.

그런데 제가 생각했던 것과는 다르게 router.query 는 빈 객체가 찍혔습니다.

useEffect(() => {
  console.log(router.query) // {}
}, [router])

router push 로 query 를 지정해서 페이지를 이동시켰는데 왜 query 가 빈 객체로 나오는지 의문을 갖고 검색을 해보니

Next.js 에서 정적 파일 최적화에 의해 router 의 query 객체는 빈 상태로 제공이 된다고 합니다.

Rendering: Automatic Static Optimization


✨ window.location.search 로 파라미터 가져오기 성공

그래서 다음으로 시도한 방법은 window.location.search 를 이용해 파라미터를 가져올 수 있도록 시도했습니다.

해당 데이터는 URL 의 매개변수가 포함된 문자열을 갖고 올 수 있는 속성입니다.

일단, useEffect 의 의존성 배열에 window.location.search 를 넣어준 뒤 해당 값을 URLSearchParams 함수를 이용해서 파라미터를 추출합니다.

useEffect(() => {
  const page = getParamToNumber(window.location.search, 'page') || 1
  const count = getParamToNumber(window.location.search, 'count') || 10
  const status = getParam(window.location.search, 'status') || 'requested'
}, [window.location.search])

// 파라미터 값을 가져올 수 있는 공통 함수를 만듦
const getParam = (paramStr, name) => {
  return new URLSearchParams(paramStr).get(name)
}
const getParamToNumber = (paramStr, name) => {
  return Number(new URLSearchParams(paramStr).get(name))
}

그 다음, 추출한 파라미터 값을 setState 를 통해 변경하여 최신화 시켜줍니다.

useEffect(() => {
  const page = getParamToNumber(window.location.search, 'page') || 1
  const count = getParamToNumber(window.location.search, 'count') || 10
  const status = getParam(window.location.search, 'status') || 'requested'
  **setPage(page)
  setCount(count)
  setStatus(status)**
}, [window.location.search])

각 검색 조건인 state 값이 변경될 때마다 API 가 호출될 수 있도록 설정해두었기 때문에 파라미터에서 추출된 값으로 검색이 됩니다.


검색 조건 status 초기값 설정

이제 정말 링크 그대로 검색결과가 유지되는지 새 창에서 접속해 볼 차례입니다.

지금은 반품 상태 중 ‘반품 수거완료’ 인 목록들만 보고 싶기 때문에 반품 수거완료로 필터링된 페이지의 URL 을 복사해서 접속해보겠습니다.

원하는 ‘반품 수거완료’ 상태인 데이터들을 잘 불러왔고, 결과 목록에도 잘 뜨는 것을 확인할 수 있습니다.

그런데 자세히 보면 status 가 처음에는 requested 로 API 를 호출하고 그 다음에 collected 로 호출하면서

불필요한 API 호출이 일어나고 있습니다.

이렇게 불필요한 호출이 일어나게 되는 원인은 status 의 초기값 설정에 있습니다.

처음 status 의 상태값의 초기값을 requested 로 설정을 해줌으로써 reqeusted 상태로 한 번 API 가 호출되고

window.location.search 를 useEffect 로 감지해서 다시 한 번 더 status 값을 변경해주기 때문에

“초기값 requested 로 API 호출 → window.location.search 로 추출된 파라미터 값인 collected 로 다시 API 호출” 이 되고 있었습니다.

제가 필요한 초기값은 무조건 requested 가 아니라 파라미터에서 추출된 데이터가 필요하기 때문에

useState 내부에서 파라미터에서 추출한 값을 초기값으로 지정해주겠습니다.

const [status, setStatus] = useState(getParam(window.location.search, 'status') || 'requested')

불필요한 API 호출없이 원하는 조건에 대해서만 불러오고 있는 것을 확인할 수 있습니다.

반품 상태인 status 뿐만 아니라 page, count 도 모두 동일하게 위처럼 설정하면 파라미터값으로 검색 조건을 기억할 수 있습니다.


정리


  1. 검색 조건을 useState 로 지정해주고, 초기값은 window.location.search 에서 추출한 파라미터 값 지정
  2. 검색할 때 router.push 를 이용해 검색 조건은 query 옵션에 넣어 URL 을 이동
  3. window.location.search 를 useEffect 로 감지해서 변경된 파라미터를 가져온 뒤 추출하고 각 검색 조건 setStatus 로 변경
  4. useQuery 에 각 검색 조건 state 값들을 쿼리키로 지정해 변경될 때마다 알아서 API 호출할 수 있도록 지정 (react query 사용 전제)
profile
🌸 좋은 코드를 작성하고 싶은 프론트엔드 개발자 ✨

0개의 댓글