[React-Router] useSearchParams - 쿼리 스트링 값 가져오기

현채은·2024년 2월 22일
1
post-thumbnail

쿼리스트링 (Query String)

쿼리 스트링은 URL의 한 부분으로, 요청하는 URL에 부가정보를 추가할 때 사용된다.

  • 기존 URL은 단순한 형태의 요청과 응답으로 주고 받았지만, 쿼리 스트링을 사용하면 조건에 맞는 특정 형태의 정보를 요청하고 받을 수 있다.
  • ex> 규모가 크고 복잡한 애플리케이션의 10000개의 상품 종류 중 판매량 순 상위10개, 최신등록순 10개 ・・・ 등 특정 기준으로 편집된 정보를 받아올 수 있다.

➡️ 위 상황과 같이 '상품 리스트를 최신순으로 상위 10개만 보여줘' 라고 구체적인 요청을 작성하기 위해 쿼리스트링을 사용한다.

쿼리 스트링의 형태

쿼리스트링은 문자열 형태이며. key = value로 표현한다.
각 페어의 구분은 &로 한다.

http://www.example/com/products?sort=popular
http://www.example/com/products?sort=popular&direction=derc

쿼리 스트링을 포함한 라우팅

쿼리스트링은 URL에 부가적인 정보를 포함하는 역할을 하기 때문에 라우터 컴포넌트에도 특별한 설정이 필요없다.
아래 예시처럼 링크 역할을 하는 컴포넌트에 쿼리스트링이 포함된 주소를 전달하면 된다.

import { useLocation } from 'react-router-dom'

// 컴포넌트 안에서 데이터를 변수에 담고 확인
const location = useLocation();
console.log(location);
console.log(location.search) // ?sort=popular

위와 같이 코드를 작성하면 콘솔창에 여러 객체가 나오고, 그 중 search 프로퍼티가 쿼리스트링 값을 담고 있는 것을 확인할 수 있다.

가져온 값에서 popular만 뽑아서 사용하려면 별도의 작업이 필요한데,
이러한 상황에서 간단하게 원하는 매개변수의 value를 가져올 수 있는 방법이 useSearchParams이다.

const [searchParams, setSearchParams] = useSearchParams();

searchParams는 URLSearchParams 객체이면서 쿼리스트링을 다루기 위한 여러 메서드를 제공해준다.

  • setSearchParams : 인자에 객체, 문자열을 넣어주면 현재 url의 쿼리스트링을 변경하는 기능을 제공해준다.

자주 사용되는 searchParams 메서드

  • searchParams.get(key) : 특정한 key의 value를 가져오는 메서드 ( 해당 key의 value가 두개라면 제일 먼저 나온 value만 리턴 )
  • searchParams.getAll(key) : 특정 key에 해당하는 모든 value를 가져오는 메서드
  • searchParams.toString() : 쿼리 스트링을 string 형태로 리턴시켜주는 메서드
  • searchParams.set(key, value) : 인자로 전달한 key값을 value로 설정, 기존 값이 존재했다면 해당 값은 삭제된다.
  • searchParams.append(key, value) : 기존 값을 변경하거나 삭제하지 않고 추가하는 방식

searchParams을 변경하는 메서드로 값을 변경해도 실제 uel 쿼리 스트링은 변경되지 않는다. 이를 변경하려면 setSearchParams에 searchParams를 인자로 전달해야 변경할 수 있다.

코드예시

import { useSearchParams } from 'react-router-dom'

useSearchParams를 import하고 setSortParams 함수를 만든다.
➡️ set 메서드를 통해 sort라는 키에 clear라는 value 값을 설정한 후 현재 url의 쿼리스트링을 변경한다.

const [ searchParams, setSearchParams ] = useSearchParams();

const setSortParams = () => {
  searchParams.set('sort', 'clear');
  setSearchParams(searchParams);
};

여기서 append 메서드를 사용하면 기존 키의 값은 유지하며 추가로 sort라는 키에 hello 라는 값을 추가할 수 있다.

const appendSortParams = () => {
  searchParams.append('sort', 'hello');
  setSearchParams(searchParams);
};

실제 활용 예시 (페이지네이션)

쿼리 스트링은 검색, 필터링, 페이지네이션 등에 다양하게 활용되고 있다. 실제 프로젝트를 진행할 때에는 필터링 목적으로 사용했기 때문에 페이지네이션을 예시로 들어봐야겠다.

먼저 페이지네이션을 위해서는 offsetlimit라는 2가지 기준이 필요하다.

  • offset : 몇번째 아이템부터 보여줄 것인가 ?
  • limit : 아이템 몇개를 보여줄래 ?
    예를 들어 0번째 이후로 10개의 아이템을 보여줘를 쿼리스트링으로 표현하면
`offset=0&limit=10`

라고 표현할 수 있다.

실제 페이지네이션을 구현한 코드를 살펴보면

import React, { useState, useEffect } from 'React'
import { useSearchParams } from 'react-router-dom'

const List = () => {
  const [searchParams, setSearchParams ] = useSearchParams(); // 쿼리스트링을 searchParams 형태로 가져오기
  const offset = searchParams.get('offset'); // offset의 값 변수에 저장
  const limit = searchParams.get('limit'); // limit 값 변수에 저장
  return (
    <section>
      <h1>This is post</h1>
    </section>
  )
}

export default List;

이제 api 호출로 받아온 데이터를 담을 state를 생성하고 useEffect, fetch로 전체 포스트의 데이터를 받아온다. 이때 사용하는 api주소에 위에 저장한 offsetlimit 값을 넣는다.
의존성 배열에는 offsetlimit를 넣어서 해당 값이 변경될 때 마다 매번 해당하는 쿼리스트링을 포함하는 데이터를 받아오도록 한다.

const [post, setPost] = useState([]);

useEffect (() => {
  fetch(`https://jsonplaceholder.~.com/posts?_start=${offset}&_limit=${limit}`)
  .then((responese) => response.json())
  .then((res) => setPost(res));
}, [offset, limit]);

다음은 페이지 번호를 표시하고, 해당 페이지마다 10개씩 포스트를 보여주는 함수를 생성합니다.
➡️ 1페이지 (1-10번 게시물) , 2페이지(11-20 게시물)...
해당 함수는 searchParams를 변경하고 setSearchParams를 통해 쿼리스트링을 변경한다. 이때 limit는 기존 값 10을 유지하면 되기 때문에 offset값만 0, 10, 20으로 변경시켜주면 된다.

const movePage = (pageNumber) => {
  searchParams.set('offset' , (pageNumber -1)*10);
  setSearchParams(searchParams);
}

이제 생성한 버튼 태그에서 페이지 넘버를 인자로 넣은 뒤 위 함수를 실행시켜주면 페이지네이션 완성 ⭐️

<div>
  <button onClick = {() => movePage(1)}>1</button>
  <button onClick = {() => movePage(2)}>2</button>
  <button onClick = {() => movePage(3)}>3</button>
</div>

추가적으로 알아둘 내용은 프론트엔드에서 사용하는 쿼리스트링과 백엔드에 보내는 쿼리스트링의 key값이 동일할 필요는 없다는 것 !
➡️ 서로 다른 별개의 리소스를 관리하는 path parameter와 쿼리스트링은 다른 것이기 때문
➡️ state로 offset, limit 값을 관리하는 경우 페이지네이션으로 이동할 때 초기화되기 때문에 쿼리스트링으로 관리하는 것이 좋음

전체 코드 보기

import React, { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import './List.css';

const List = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  const offset = searchParams.get('offset');
  const limit = searchParams.get('limit');

  const [posts, setPosts] = useState([]);

  useEffect(() => {
    fetch(
      `https://json~com/posts?_limit=${limit}&_start=${offset}`
    )
      .then((response) => response.json())
      .then((result) => setPosts(result));
  }, [offset, limit]);

  const movePage = (pageNumber) => {
    // 1
    searchParams.set('offset', (pageNumber - 1) * 10);
    setSearchParams(searchParams);
  };

  return (
    <section>
      <h1>This is Posts</h1>
      {posts.map(({ id, title }) => (
        <article key={id}>
          <p>
            <div>id:{id}</div>
            <div>title:{title}</div>
          </p>
        </article>
      ))}
      <div>
        <button onClick={() => movePage(1)}>1</button>
        <button onClick={() => movePage(2)}>2</button> 
        <button onClick={() => movePage(3)}>3</button> 
      </div>
    </section>
  );
};

export default List;
profile
개발 기록 공간

0개의 댓글