- 카드를 클릭하면, onClick 이벤트시 발생하는 navigate 함수를 통해 /product/1 로 이동한다.
- URL 이 /product/1 로 변하면, Router 컴포넌트에 정의되어 있는 path='/product/:id' 에 따라, ProductDetail 컴포넌트가 마운트 된다.
- ProductDetail 컴포넌트에서는 백엔드에 id 가 1 인 아이템에 대한 정보를 요청
- 응답으로 받은 정보를 setData 함수를 통해 data 라는 state에 저장하고, 이를 통해 상세 페이지 UI 가 그려진다.
2번에서, ProductDetail 컴포넌트의 useEffect 훅을 통해 백엔드에 id 가 1 에 해당하는 정보를 요청했다. 그런데, 1 은 URL 에 담겨 있다(/product/1). ProductDetail 컴포넌트에서는 이것을 어떻게 가져올 수 있을까 ?
React Router 에서는 useNavigate, useLocation, useParams 라는 라우팅 관련한 훅을 제공한다. 이 중 useParams 훅을 사용하면 url 에 담겨있는 id 값을 가져올 수 있다.
useNavigate Hook
useNavigate
function Product(props) {
const navigate = useNavigate();
const goToDetail = () => {
navigate(`/product/${props.id}`);
}
return (
<div className="productContainer" onClick={goToDetail}>
...
</div>
)
}
useNavigate 훅을 실행하면 페이지를 이동시키는(url을 변경시키는) 함수를 반환한다. 위 예제 코드에서 해당 함수를 navigate 라는 변수에 할당하였습니다. 따라서, navigate()와 같은 방식으로 함수를 호출할 수 있다.
navigate() 함수의 인자에 이동하고자 하는 url(ex. /products)을 전달하면, 해당 url로 화면을 이동합니다.
navigate('/product/1'); // '/product/1' 로 이동
인자에 정수값을 넣어주면 브라우저 방문 기록에 남아있는 경로들을 앞 뒤로 탐색할 수도 있습니다.
navigate(-1); // 뒤로 가기
navigate(-2); // 뒤로 2페이지 가기
navigate(1); // 앞으로 가기
useLocation Hook
useLocation
function ProductDetail(props) {
const location = useLocation();
console.log(location);
return (
...
)
}
useLocation 훅을 실행하면 경로 정보를 담고 있는 객체 를 반환합니다. 위 코드에서 해당 객체를 location 이라는 변수에 할당해 주었습니다. location 변수를 콘솔로 출력해 보면 다음과 같은 로그가 출력 됩니다.
{
pathname: '/product/1',
search: '',
hash: '',
state: null,
key: 'default'
}
여러가지 정보가 있는데, 여기서 주목할 부분은 pathname 과 search 프로퍼티 입니다.
- pathname: 현재 경로 값
- search: 현재 경로의 query parameter 값
useParams Hook
useParams
// 현재경로: /product/1
function ProductDetail(props) {
const params = useParams();
console.log(params);
return (
...
)
}
useParams 훅을 실행하면 path parameter 정보를 담고 있는 객체 를 반환합니다. 위 코드에서 해당 객체를 params 라는 변수에 할당해 주었습니다. params 변수를 콘솔로 출력해 보면 다음과 같은 로그가 출력 됩니다.
{
id: 1
}
여기서 id 라는 프로퍼티 키 네임은 Router 에서 :id 로 표기해준 값 입니다.
<BrowserRouter>
<Routes>
<Route path='/product/:id' element={<ProductDetail />} />
</Routes>
</BrowserRouter>
만약 :productId 라고 표기 했다면 다음과 같은 객체가 출력됩니다.
{
productId: 1
}
정리하자면,
- useNavigate 훅은 url 를 변경하는 함수 를 반환하고
- useLocation 훅은 현재 경로 정보를 담고 있는 객체 를 반환하고
- useParams 훅은 Router 에 등록해준 path parameter 정보를 담고 있는 객체 를 반환합니다.
4. useParams().id
다시 돌아와서, 어떻게 URL 에 담겨있는 id 값을 가져올 수 있을까요?
useParams 훅을 이용하여 가져올 수 있습니다. Path Parameter 로 명시해둔 값은 useParams 훅이 리턴하는 객체에 담기기 때문입니다.
// ProductDetail.js
// current url -> localhost:3000/product/1
function ProductDetail() {
const params = useParams();
console.log(params.id) // 1
return (
...
);
}
따라서 useEffect 훅에서 해당 id 값을 통해 서버에 요청을 보내는 것을 통해 원하는 정보를 받아올 수 있습니다.
useEffect(() => {
fetch(`${API}/${params.id}`)
.then(res => res.json())
.then(res => setData(res));
},[]);
위에서 봤던 예제를 다시한번 보자.
- 리스트 페이지의 개별 상품을 클릭 → navigate("/product/1") 로 상세 페이지로 이동합니다.
- 상세 페이지로 이동하면 url은 "http://localhost:3000/product/1" 과 같이 변경되어 있습니다.
- 페이지에 필요한 데이터를 useEffect 에서 fetching 합니다.
- 필요한 id는 URL에 존재하므로 useParams().id 에서 가져올 수 있습니다.
- 해당 id를 가지고 백엔드에서 만들어준 API를 호출합니다.
- function ProductDetail() { const params = useParams(); useEffect(() => { const productId = params.id; fetch(`http://123.456.789:8000/products/${productId}`) // 1 .then(res => res.json()) .then(res => setData(res)); },[]); return ( ... ) }
- 서버에서 가져온 데이터(res)를 컴포넌트의 data state 에 저장해 줍니다.
- state 에 담긴 데이터로 컴포넌트 UI 를 render 해줍니다.