다른 경로(url 주소)에 따라 다른 View(화면)를 보여주는 것.
사용자가 웹 애플리케이션과 상호 작용하는 방식을 획기적으로 바꾼 기술.
사용자가 다른 뷰로 이동할 때 애플리케이션은 뷰를 동적으로 다시 그림. MPA(Multi Page Application) 대비 페이지 간 이동 시 사용자가 느낄 수 있는 딜레이를 제거해 일반적으로 더 나은 UX를 제공. (페이지 전체를 새로고침 하지 않기 때문! )
"/" => <App />
"/users" => <Users />
"/products" => <Products />
정적이지 않은, 동적일 수 있는 경로에 대하여 라우팅을 하는 것.
라우트 경로에 특정 값을 넣어 해당하는 페이지로 이동할 수 있게 하는 것.
url 을 살펴보면 url 마지막에 특정 id 값이 들어가고(/32692, /53424), 해당 id 값에 따라 서로 다른 상세 페이지 정보가 화면에 그려지는 것을 볼 수 있음. id 값에 따라 무수히 많은 url 이 나타날 것이고, 각각의 모든 url 에 대해 미리 경로의 형태와 갯수를 결정할 수 없게 됨.
즉, URL에 들어갈 id를 변수처럼 다뤄야 할 필요성이 생긴 것.
Path Parameter
// Bad
"/users/1" => <Users id={1} />
"/users/2" => <Users id={2} />
"/users/3" => <Users id={3} />
"/users/4" => <Users id={4} />
"/users/5" => <Users id={5} />
// Good
"/users/:id" => <Users /> // useParams().id
localhost:3000/product/2
localhost:3000/product/45
localhost:3000/product/125
라우트 경로 끝에 들어가는 각기 다른 id 값들이 들어감. 2, 45, 125 url 경로에서 달라지는 부분을 저장하는 매개 변수를 Path Parameter 라고 함.
Path Parameter 는 Router 컴포넌트에서 다음과 같이 정의.
<BrowserRouter>
<Routes>
<Route path='/product/**:id**' element={<ProductDetail />} />
</Routes>
</BrowserRouter>
: 는 Path Parameter 가 올 것임을 의미함.
id 는 해당 Path Parameter 의 이름을 의미함. 변수 명을 짓듯이, 임의의 이름을 지정해줄 수 있음. ex) :productId
1. 카드를 클릭하면, onClick 이벤트시 발생하는 navigate 함수를 통해 /product/1 로 이동함.
URL 이 /product/1 로 변하면, Router 컴포넌트에 정의되어 있는 path='/product/:id' 에 따라, ProductDetail 컴포넌트가 마운트 됨.
2. ProductDetail 컴포넌트에서는 백엔드에 id 가 1 인 아이템에 대한 정보를 요청함.
3. 응답으로 받은 정보를 setData 함수를 통해 data 라는 state에 저장하고, 이를 통해 상세 페이지 UI 가 그려짐.
2번 스텝에서, ProductDetail 컴포넌트의 useEffect 훅을 통해 백엔드에 id 가 1 에 해당하는 정보를 요청 함. 그런데, 1 은 URL 에 담겨 있음.(/product/1). ProductDetail 컴포넌트에서는 이것을 어떻게 가져올 수 있을까요?
useNavigate Hook
url 에 담겨있는 id 값을 가져올 수 있음.
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
function ProductDetail(props) {
const location = useLocation();
console.log(location);
return (
...
)
}
useLocation 훅을 실행하면 경로 정보를 담고 있는 객체 를 반환함. 위 코드에서 해당 객체를 location 이라는 변수에 할당해 줌. location 변수를 콘솔로 출력해 보면 다음과 같은 로그가 출력됨.
{
pathname: '/product/1',
search: '',
hash: '',
state: null,
key: 'default'
}
pathname: 현재 경로 값
search: 현재 경로의 query parameter 값
useParams Hook
// 현재경로: /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 정보를 담고 있는 객체 를 반환
어떻게 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 해줌.