Query String feat. useLocation & useSearchParams

Moon Hayden·2022년 9월 16일
0

우리가 웹 페이지를 돌아다니다 보면 어떤 상품이나 정보가 리스트로 나열 되어있는 것을 볼 수 있다. 만약 1억 개가 넘어가는 리스트가 있다면 우리는 쉽게 그 리스트를 볼수 없을것이다. 이때 Query String은 그 리스트를 최신순, 평점순 등 구체적인 요청이 가능하게 해준다.

예시를 들어 Products를 인기순으로 정렬한 리스트를 보고싶을땐
https://www.example.com/products?sort=popular
products뒤에 ? 로 Query String 의 시작을 알리고 그 뒤에 key=value 의 형태로 sort=popular 라고 입력하여 인기순 리스트를 얻을수 있다.

useLocation

Query String를 이해했다면 이젠 컴포넌트에서 이 값을 컴포넌트에서 가져올 수 있어야 한다. 이때 사용하는 것이 useLocation 이다.

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

const List = () => {
  const location = useLocation();
  const queryString = location.search;

  return (
    <section>
      <h1>This is List Page</h1>
      <p>
        쿼리 스트링: <b>{queryString}</b>
      </p>
    </section>
  );
};

export default List;

useLocation을 선언한 후 이 안의 Search 값을 가지고 오면 Query String의 값을 아래와 같이 얻을 수 있다.

useLocation가 포함하고 있는 다른 프로퍼티에 대해 알고싶다면 여기 를 클릭하여 공식 문서를 참고해보자.

useSearchParams

Query String을 요청에 따라 수정해주며 원하는 값을 자유자제로 가지고 오는것도 필요하다. 이때 사용하는것이 useSearchParams 이다. useSearchParams는 useState와 비슷하게 배열의 형태로 searchParams와 setSearchParams 함수를 리턴해 준다. 여기서 searchParams는 URLSearchParams 객체이며 URLSearchParams 객체는 쿼리 스트링을 다루기 위한 여러 편리한 메서드를 제공해 준다.
const [searchParams, setSearchParams] = useSearchParams();
자주 사용되는 메서드는 아래와 같다.

주의할점
earchParams를 변경하는 메서드를 이용해서 searchParams의 값을 변경하더라도 실제 URL의 쿼리 스트링은 변경되지 않는다. 변경된 searchParams를 이용해서 실제 쿼리 스트링을 변경시키려면 setSearchParams 함수에 searchParams를 인자로 전달하면서 호출해야 한다.

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

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

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

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

Pagination

Query String를 활용하는 다른 예시로 Pagination이 있다. 구현을 위해서는 offset 과 limit 두 가지 기준이 필요한데 offset은 몇번째 아이템 부터 보여줄지, limit은 몇개의 아이템을 보여줄지를 뜻 한다.

예시
https://jsonplaceholder.typicode.com/posts?_offset=0&_limit=10
0번째 이후로 10개의 아이템을 보여줘 라는 뜻이 된다.

아래는 useSearchParams를 사용하여 컴포넌트 안에서 페이지 번호를 만들고 페이지를 이동하는 기능을 구현해 보겠다.

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://jsonplaceholder.typicode.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> {/* 2 */}
        <button onClick={() => movePage(2)}>2</button> {/* 2 */}
        <button onClick={() => movePage(3)}>3</button> {/* 2 */}
      </div>
    </section>
  );
};

export default List;

useEffect, useState를 활용해 API를 호출 하고 offset의 값이 변경 될 때마다 다시 렌더링 되야하기 때문에 의존성 배열에 offset을 넣어준다.

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

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

const offset = searchParams.get('offset'); offset의 값에 접근을 하고
const movePage = (pageNumber) => { // 1 searchParams.set('offset', (pageNumber - 1) * 10); setSearchParams(searchParams); };
movePage 변수를 선언해준 뒤

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

아래 버튼의 onClick 콜백 함수에 위와같이 넣어주면 페이지 버튼이 클릭 될 때마다 요청에 맞게 페이지 마다 정보가 나타나지게 된다.

느낀점

프로젝트 기간동안 Query String은 글로 정리 해놔야 겠다는 생각을 했는데 드디어 오늘 정리 하였다. 적다보니 글이 조금 길어지긴 했지만 주제에 대한 이해도가 더욱 단단히 자리잡은것 같아서 보람이 있다. 아직 정리 해야할 개념들이 많은데 차근히 하나하나 추후 업로드 하도록 하겠다.

profile
매일 꾸준히 성장하는 마라토너 개발자 🏃‍♂️

0개의 댓글