[React #13] 동적 라우팅과 Path Parameter, 그리고 관련 Hooks

라우팅을 위한 기본 코드 구조

// index.html
<!DOCTYPE html>
  <head>
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
// index.js
ReactDOM.render(<Router />, document.getElementById("root"));
// Router.js
const Router = () => {
  return (
    <BrowserRouter>
			<Nav />
      <Routes>
        <Route path="/" element={<App />} />
        <Route path="/users" element={<Users />} />
        <Route path="/products" element={<Products />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
			<Footer />
    </BrowserRouter>
  );
};
  • index.html : public/index.html에 위치하며 React 페이지 로드 시 가장 먼저 호출되는 영역
  • index.js : React 앱을 렌더하고 index.html의 div#root 이하에 끼워넣는 역할
  • Router.js : React 앱이 경로에 따라 어떤 컴포넌트를 보여줄지 결정하는 역할 (화면 바꿔 끼우기)

정적 라우팅(Static Routing)이란?

"/"         => <App />
"/users"    => <Users />
"/products" => <Products />

동적 라우팅(Dynamic Routing)이란?

  • 일반적인 웹 사이트는 전체 아이템이 보여지는 리스트 페이지와 해당 아이템의 디테일 한 정보로 구성된상세 페이지로 구성된다.
  • 도메인 주소 끝에 해당 아이템의 id값이 추가되어 페이지를 이동하고, 이동한 페이지에서는 id값에 해당하는 데이터가 보여지는 것을 볼 수 있다.
    -> url 을 살펴보면 url 마지막에 특정 id 값이 들어가고(/32692, /53424), 해당 id 값에 따라 서로 다른 상세 페이지 정보가 화면에 그려지는 것을 볼 수 있다.
    id 값에 따라 무수히 많은 url 이 나타날 것이고, 각각의 모든 url 에 대해 미리 경로의 형태와 갯수를 결정할 수 없게 된다.
  • 즉, URL에 들어갈 id를 변수처럼 다뤄야 할 필요성이 생긴 것입니다.
  • 이처럼 정적이지 않은, 동적일 수 있는 경로에 대하여 라우팅을 하는 것을 동적 라우팅(Dynamic Routing)이라고 한다.
    => 라우트 경로에 특정 값을 넣어 해당하는 페이지로 이동할 수 있게 하는 것을 동적 라우팅이라고 한다.

동적인 라우팅을 처리하는 방법: Path Parameter, Query Parameter

  • 동적인 경로를 처리할 수 있는 방법은 Path Parameter와 Query Parameter가 있다.
    1) 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

2) Query Parameter

// Bad
"/search?keyword=리액트"    : <Search keyword="리액트" />
"/search?keyword=라우팅"    : <Search keyword="라우팅" />
"/search?keyword=쿼리스트링" : <Search keyword="쿼리스트링" />
"/search?keyword=SPA"     : <Search keyword="SPA" />
  
 // Good
"/search?keyword=something" : <Search /> // useLocation().search

Path Parameter

localhost:3000/product/2
localhost:3000/product/45
localhost:3000/product/125
  • 라우트 경로 끝에 들어가는 각기 다른 id 값들을 저장하는 매개 변수
<Router>
  <Switch>
    <Route exact path='/product/:id' component ={producitDetail} />
  </Switch>
</Router>
  • :는 Path Parameter가 올 것을 의미
  • id는 해당 Path Prameter의 이름

동적 라우팅 흐름


1. 카드를 클릭하면, onClick 이벤트시 발생하는 navigate 함수를 통해 /product/1 로 이동. URL 이 /product/1 로 변하면, Router 컴포넌트에 정의되어 있는path='/product/:id' 에 따라, ProductDetail 컴포넌트 마운트
2. ProductDetail 컴포넌트에서는 백엔드에 id 가 1 인 아이템에 대한 정보 요청
3. 응답으로 받은 정보를 setData 함수를 통해 data 라는 state에 저장하고, 이를 통해 상세 페이지 UI가 그려진다.

useNavigate, useLocation, useParams Hook

  • React Router 에서는 useNavigate, useLocation, useParams 라는 라우팅 관련한 훅을 제공한다.

useNavigate Hook

function Product(props) {
  const navigate = useNavigate();
  
  const goToDeatil = () => {
    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: '', // 현재 경로의 query parameter 값
  hash: '', 
  state: null, 
  key: 'default'
}

useParams Hook

// 현재경로: /product/1

function ProductDetail(props) {
  const params = useParams();
  
  console.log(params);
  
  return(
    ...
   )
    }

//반환 
{
  id: 1 //id 프로퍼티 키 네임은 Router에서 :id로 표기해준 값
}
  • url에 담겨있는 path parameter에 대한 정보를 가져올 수 있다.
  • 정보는 parameter 객체로 반환하고, route에서 지정한 key 이름으로 반환한다.
<BrowserRouter>
	<Routes>
		<Route path='/product/:id' element={<ProductDetail />} />
	</Routes>
</BrowserRouter>

useParams().id

  • URL에 담긴 id 값을 가져올 때 useParam 훅을 이용한다. 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를 호출한다.
      ```jsx
      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 해준다.

좋은 웹페이지 즐겨찾기