[React] 쿼리 스트링(Query String)

Yuzu·2023년 1월 28일
1
post-custom-banner
  • URL의 한 부분으로서, 요청하고자 하는 URL에 부가적인 정보를 포함하고 싶을 때 사용 (구체적으로 더 정렬되고 특정된 형태의 정보를 요청)

형태

https://www.example.com/products?sort=popular&color=red

쿼리스트링: key=value 형태의 문자열로 표현 (key=value 페어의 개수 제한은 없음)
? : 쿼리스트링의 시작 표시 (start of parameters)
& : key=value 페어 구분 표시 (separator)

사용 방법

Routing

  • Router 컴포넌트 설정 X
  • Link 컴포넌트나 navigate 함수의 인자에 쿼리 스트링이 포함된 URL을 전달
ex. <Link to="/list?sort=popular" />, navigate("/list?sort=popular")

쿼리 스트링 값 가져오기

  • react-router-dom에서는 쿼리 스트링의 값을 편하게 가져올 수 있는 hook 들을 제공
  • state처럼 쿼리 스트링의 값이 바뀌면 컴포넌트를 리렌더링 해주는 기능이 있다.

1. useLocation hook

현재 Location 객체를 return

Location 객체: 현재 위치(URL)에 포함된 여러 가지 정보를 가지고 있고 각각의 정보를 pathname, search, hash, state, key 등의 프로퍼티로 표현함
search: 쿼리 스트링을 나타내는 프로퍼티로 URL 중 쿼리 스트링에 대한 정보가 문자열 형태로 저장되어 있다.

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

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

단점: 원하는 값만 가져오려면 문자열(?sort=popular)을 자바스크립트를 통해서 Parsing 해야함

2. useSearchParams hook

쿼리 스트링의 값을 이용해서 URLSearchParams 객체를 return

URLSearchParams 객체: 쿼리 스트링에서 원하는 값만 얻어낼 수 있도록 다양한 메서드를 제공해 주는 객체

const [searchParams, setSearchParams] = useSearchParams();

useSearchParams hook을 호출하면 useState와 비슷하게 배열의 형태로 searchParams와 setSearchParams 함수를 리턴해줍니다.

searchParams: URLSearchParams 객체
setSearchParams 함수: 인자로 객체 또는 문자열을 넣어서 호출하면 현재 URL의 쿼리 스트링을 변경하는 기능을 제공 (컴포넌트 안에서 쿼리 스트링을 변경하고자 할 때 사용)

searchParams에 정의된 메서드

  1. 값을 읽어오는 메서드
  • searchParams.get(key) : 특정한 key의 value를 가져오는 메서드
    원하는 쿼리 스트링의 key를 인자로 넣어서 메서드를 호출하면 해당 key에 부합하는 value가 리턴된다.
  • searchParams.getAll(key) : 특정한 key에 부합하는 value가 두 개 이상일 경우 get 메서드는 제일 먼저 나온 value만 리턴해준다. getAll 메서드는 해당 key에 해당하는 모든 value 값들을 배열의 형태로 리턴해준다.
예시) ?sort=popular&sort=latest

searchParams.get("sort") // "popular"
searchParams.getAll("sort") // ["popular","latest"]
  • searchParams.toString() : 쿼리 스트링의 값을 그대로 string 형태로 리턴
searchParams.toString() // "?sort=popular&sort=latest"
  1. 값을 변경하는 메서드
    searchParams의 값을 변경하더라도 실제 URL의 쿼리 스트링은 변경되지 않는다. 실제 쿼리 스트링을 변경시키려면 setSearchParams 함수에 searchParams를 인자로 전달하면서 호출해야 한다.
  • searchParams.set(key, value) : 메서드를 호출하면서 인자로 전달한 key 값을 value로 설정하는 메서드
    만약 동일한 key에 여러 value가 이미 존재하고 있었다면, set 메서드를 호출하면서 설정한 값 외에는 삭제된다.
  • searchParams.append(key, value) : 메서드를 호출하면서 인자로 전달한 key 값을 value로 추가하는 메서드
    기존의 값들을 변경하거나 삭제하지 않고 추가하는 방식으로 동작한다.
searchParams.set("sort", "clear")
searchParams.toString() // "?sort=clear"

searchParams.append("sort", "clear")
searchParams.toString() // sort=popular&sort=latest&sort=clear"

//setSearchParams 함수 호출
  const [searchParams, setSearchParams] = useSearchParams();

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

  const appendSortParams = () => {
    searchParams.append('sort', 'hello-world');
    setSearchParams(searchParams);
  };
  
 return (
 .
 .
    <button onClick={setSortParams}>setSortParams</button>
    <button onClick={appendSortParams}>appendSortParams</button>
);

페이지네이션

  • 쿼리 스트링을 이용해 전체 아이템 중에서 내가 보고자 하는 범위를 표현

offset(start): 몇 번째 아이템부터 보여줄 것인가, “n번째 이후로”
limit(size): 한 번에 몇 개를 보여줄 것인가, “n개의 아이템을 보여줘”

ex.
요청: “0번째 이후로 10개의 아이템을 보여줘”
쿼리 스트링: ?offset=0&limit=10

구현 방법

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

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

  useEffect(() => {                                
    fetch(
      `https://jsonplaceholder.typicode.com/posts?_start=${offset}&_limit=${limit}`                  // 3
    )
      .then((response) => response.json())
      .then((result) => setPosts(result));		   // 4
  }, [offset, limit]);                             // 5
  1. 쿼리 스트링에서 offset과 limit의 값을 각각 offset, limit 변수에 저장
  2. posts란 state를 만들고 초깃값으로 빈 배열을 설정
  3. 그냥 요청을 하면 전체 포스트 데이터를 응답해 주지만, _start , _limit 두 개의 쿼리 스트링을 이용해서 요청을 보내면 _start에 적힌 숫자 이후의 포스트부터 _limit에 적힌 개수만큼의 포스트만 응답해 준다.
    쿼리스트링에 _start key에 offset 값을, _limit key에 limit 값을 담아서 요청을 보낸다.
  4. setPosts 함수를 이용해서 응답 값을 posts state에 저장
  5. API 호출을 하고 이를 posts state에 저장하는 과정이 offset 또는 limit 값이 변경될 때마다 매번 발생해야 하기 때문에 의존성 배열에 offset과 limit을 넣어준다.

페이지 이동 기능

  • 페이지 번호에 따라 페이지를 이동하는 기능 구현
  const movePage = (pageNumber) => {
    searchParams.set('offset', (pageNumber - 1) * 10);
    setSearchParams(searchParams);
  };  		// 1
  
return(      
	<div>
        <button onClick={() => movePage(1)}>1</button> 
        <button onClick={() => movePage(2)}>2</button> 
        <button onClick={() => movePage(3)}>3</button>
    </div>		// 2
      )
  1. movePage란 함수에서 searchParams를 변경하고 setSearchParams를 통해서 쿼리 스트링을 변경하는 동작을 한다.
    limit은 기존 값인 10에서 변경하지 않아도 되니 offset의 값만 변경해 준다.

  2. 페이지 아래에 1, 2, 3 페이지를 나타내는 버튼을 만들어준다.
    button에 onClick 이벤트 리스너를 추가하여 각 버튼이 눌렸을 때 movePage 함수를 pageNumber를 인자로 전달하면서 호출하도록 한다.

해당 버튼을 눌렀을 경우 보이는 UI 변경
1페이지 버튼-> 1~10번 포스트
2페이지 버튼-> 11~20번 포스트
3페이지 버튼-> 21~30번 포스트

추가 TIP
1. 필터링, 검색 결과 등 해당 정보가 지속적으로 유지되어야 하는 경우에는 쿼리 스트링을 활용하는 것이 좋다.
2. path parameter는 완전히 다른 별개의 리소스를 표현할 때 사용 (ex. 다른 상세 페이지를 표현)
query string은 같은 리소스를 표현하되, 추가적인 정보를 포함해서 요청을 할 때 사용 (ex. 다른 정보지만 동일한 리스트 페이지를 표현)
3. 프론트엔드에서 사용하는 쿼리 스트링과 백엔드 API의 엔드 포인트에 추가하는 쿼리 스트링은 별개다. 프론트엔드 쿼리 스트링을 이용해 백엔드 API 엔드 포인트에 추가하는 쿼리 스트링을 만들 수는 있겠지만 이 두 개는 완전히 별개의 독립적인 요소이기 때문에 서로 이름(key)이 일치해야 한다거나 하는 등의 제약은 없다.

profile
냐하
post-custom-banner

0개의 댓글