https://www.example.com/products?sort=popular&color=red
쿼리스트링: key=value 형태의 문자열로 표현 (key=value 페어의 개수 제한은 없음)
? : 쿼리스트링의 시작 표시 (start of parameters)
& : key=value 페어 구분 표시 (separator)
ex. <Link to="/list?sort=popular" />, navigate("/list?sort=popular")
현재 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 해야함
쿼리 스트링의 값을 이용해서 URLSearchParams 객체를 return
URLSearchParams 객체: 쿼리 스트링에서 원하는 값만 얻어낼 수 있도록 다양한 메서드를 제공해 주는 객체
const [searchParams, setSearchParams] = useSearchParams();
useSearchParams hook을 호출하면 useState와 비슷하게 배열의 형태로 searchParams와 setSearchParams 함수를 리턴해줍니다.
searchParams: URLSearchParams 객체
setSearchParams 함수: 인자로 객체 또는 문자열을 넣어서 호출하면 현재 URL의 쿼리 스트링을 변경하는 기능을 제공 (컴포넌트 안에서 쿼리 스트링을 변경하고자 할 때 사용)
searchParams에 정의된 메서드
예시) ?sort=popular&sort=latest
searchParams.get("sort") // "popular"
searchParams.getAll("sort") // ["popular","latest"]
searchParams.toString() // "?sort=popular&sort=latest"
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
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
)
movePage란 함수에서 searchParams를 변경하고 setSearchParams를 통해서 쿼리 스트링을 변경하는 동작을 한다.
limit은 기존 값인 10에서 변경하지 않아도 되니 offset의 값만 변경해 준다.
페이지 아래에 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)이 일치해야 한다거나 하는 등의 제약은 없다.