쿼리 스트링을 다루는 useLocation과 useSearchParams (feat. useParams)

Sheryl Yun·2023년 8월 18일
0

React.js

목록 보기
12/24

정리 후 팀 노션에 올릴 용도로 정리 😌

쿼리 스트링이란?

주소창 URL 뒤에 ?로 붙는 문자열

  • ?가 시작점
  • 각 쿼리 스트링은 key=value 형태
  • 여러 개의 쿼리를 붙이려면 '&'로 연결
// 인기 순 정렬
https://www.example.com/products?sort=popular

// 인기 순 정렬 + 내림차순 정렬
https://www.example.com/products?sort=popular&direction=desc

쿼리 스트링으로 라우팅하기

이동 링크에 쿼리 스트링을 포함해서 전달하면 끝

// Link 컴포넌트 방식
<Link to="/list?sort=popular" />

// useNavigate 방식
navigate("list?sort=popular")

컴포넌트에서 쿼리 스트링 가져오기

2가지 방법이 있다.

  • useLocation
  • useSearchParams

useLocation

  • useLocation을 import하고 실행한 반환 값을 변수(location)에 담는다.
  • 이 반환 값의 search 속성으로 쿼리 스트링을 가져올 수 있다.
import { useLocation } from 'react-router-dom';

const location = useLocation();
console.log(location.search); // ?sort=popular

그런데 여기서 popular만 뽑아서 사용하면 별도의 작업이 필요해서 복잡하다.
쿼리 페어가 &로 여러 개 있다면 더더욱 그렇다.

따라서 URLSearchParams라는 객체를 활용해서 이 객체에서 제공하는 메서드로 원하는 값을 편하게 가져오자.
URLSearchParams라는 객체를 제공하는 훅이 바로 useSearchParams이다.

useSearchParams

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

const [searchParams, setSearchParams] = useSearchParams();

useSearchParams 선언은 useState와 유사하게 한다.
searchParams에 메서드를 붙여 쿼리 스트링 조작을 간편하게 할 수 있다.

자주 사용하는 메서드

값 조회

  • searchParams.get(key)

    • 해당 key의 value를 가져온다.
    • key가 갖고 있는 value가 2개 이상일 경우 맨 처음 value만 리턴한다.
  • searchParams.getAll(key)

    • 해당 key의 모든 value를 가져온다.
  • searchParams.toString()

    • 쿼리 스트링을 string 타입으로 반환한다.

값 변경

  • searchParams.set(key, value)
    • key에 value를 셋팅한다.
    • 기존 key에 value가 존재한다면 해당 value를 교체한다.
  • searchParams.append(key, value)
    • 기존 값을 변경하거나 삭제하지 않고 key에 값을 추가한다.

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

예시

  • set 메서드를 사용한 경우
  • key에 값이 여러 개일 경우 첫 번째 값만 들어가고, 기존에 이미 값이 있다면 해당 값을 교체한다.
import { useSearchParams } from 'react-router-dom';

const [searchParams, setSearchParams] = useSearchParams();

const handleSetParams = () => {
	searchParams.set('sort', 'clear');
    setSearchParams(searchParams);
}
  • append 메서드를 사용하면 기존 값을 그대로 유지한 채 새로운 값을 추가할 수 있다.
const handleAppendParams = () => {
	searchParams.append('sort', 'hello');
    setSearchParams(searchParams);
}

활용

  • 검색, 필터링, 페이지네이션
  • 페이지네이션의 경우 offset과 limit 필요
    • offset: 몇 번째부터 보여줄 것인지 (시작점)
    • limit: 몇 개까지 보여줄 것인지
      • 코드 예시: 0번째 이후로 10개씩 보여주려고 할 때
      ?offset=0&limit=10

예시

// 유저가 /list?offset=10&limit=10 으로 접속한다고 가정

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

const List = () => {
	const [searchParams, setSearchParams] = useSearchParams();
    const offset = searchParams.get('offset'); // offset 키의 value 저장 (10)
    const limit = searchParams.get('limit'); // limit 키의 value 저장 (10)
    
    return (
    	<section>
        	<h1>디스 이즈 포스트</h1>
        </section>
    );
}

여기에 다음 코드를 추가한다.

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

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

페이지 번호와 함께 해당 페이지마다 포스트를 10개씩 보여주는 함수 생성
(1번은 1-10번 포스트, 2번은 11-20번 포스트, 3번은 21-30번 포스트 등)

const movePage = (pageNumber) => {
	// set으로 searchParams 객체의 offset 키 value를 교체하고
	searchParams.set('offset', (pageNumber - 1) * 10);
    // 변경된 searchParams를 setSearchParams에 다시 넣어준다. (갱신)
    setSearchParams(searchParams);
};

버튼 태그에서 페이지 번호를 함수의 인자로 넣어서 실행

<>
	<button onClick={() => movePage(1)}>1 페이지</button>
    <button onClick={() => movePage(2)}>2 페이지</button>
    <button onClick={() => movePage(3)}>3 페이지</button>
</>

참고하기

  • 프론트엔드의 쿼리 스트링과 백엔드에 보내는 쿼리 스트링의 key는 동일하지 않을 수 있다.
  • 쿼리 스트링은 동일한 파라미터(path, 리소스)에 추가 정보를 포함한 것

offset과 limit을 컴포넌트의 state가 아닌 쿼리 스트링으로 관리하는 이유?

  • 컴포넌트의 state는 화면 이동 시(페이지네이션) 초기화된다.
  • 쿼리 스트링은 url에 정보가 담겨 있어 페이지 정보가 유지된다.
    => 필터링, 검색 결과 구현 시 특정 페이지 정보가 유지되어야 하는 경우 state가 아닌 쿼리 스트링 활용하기

BONUS - URL 관련 3가지 훅 구분하기

useLocation, useParams, useSearchParams로 가져올 수 있는 것?

예시 URL: https://www.example.com/products?sort=popular

  • useLocation
    • 파라미터 + 쿼리 스트링 (/products?sort=popular)
  • useParams
    • only 파라미터만 (/products)
  • useSearchParams
    • only 쿼리 스트링만 (?sort=popular)

=> 쿼리 스트링은 key=value로 이루어져 있는데 key와 value를 따로 구할 때 useLocation으로 가져오면 split 메서드를 사용하는 등 복잡하므로 useSearchParams로 가져와서 제공되는 메서드로 편하게 꺼내쓰자 😚

전체 코드 보기

// src/List.js

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) => {
    	// page 1일 때 offset 0, page 2일 때 offset 10
    	searchParams.set('offset', (pageNumber - 1) * 10);
        setSearchParams(searchParams);
    };
    
    return (
    	<section>
        	<h1>디스 이즈 포스트</h1>
            {posts.map(({ id, title }) => (
            	<article key={id}>
                	<p>
                    	<div>id: {id}</div>
                        <div></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
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글