이 포스트는 리액트 라우터의 최신 버전인 V6.16을 기준으로 작성되었다. 그러나 V6.4 버전 이후로 크게 변한 사항은 없고, v6.4 버전이 그전의 버전들와 많이 달라졌기 때문에 지금 보고계신 이포스트는 v6.4 이후 버전의 리액트 라우터 라고 생각하면 된다.
레이아웃은 웹 페이지의 기본적인 구조를 나타내며, 헤더나 푸터 같은 일반적으로 변하지 않는 영역이 종종 있다. 이런 고정된 영역들을 중첩 라우트를 활용해 효율적으로 관리할 수 있다. 중첩 라우트를 사용하면 여러 종류의 레이아웃을 손쉽게 적용하고 변경할 수 있다.
먼저 layout 만든다.
//App.jsx
const router = createBrowserRouter(
createRoutesFromElements(<Route path="/" element={<Layout />}></Route>)
);
//layout.jsx
import { NavLink, Outlet } from "react-router-dom";
function Layout() {
return (
<div>
<header>
<ul>
<li>
<NavLink to={"/"}>HOME</NavLink>
</li>
<li>
<NavLink to={"/ABOUT"}>ABOUT</NavLink>
</li>
<li>
<NavLink to={"/PRODUCTS"}>PRODUCTS</NavLink>
</li>
</ul>
</header>
<main>
<Outlet />
</main>
<footer>footer 영역</footer>
</div>
);
}
export default Layout;
레이아웃 컴포넌트 안에는 헤더와 푸터가 구성되어 있고, 메인 영역에는 Outlet
컴포넌트가 위치한다. 레이아웃 내에서 Outlet
컴포넌트를 사용하면 자식 라우트를 렌더링할 수 있다. 이 영역이 중첩 라우트가 표시될 구역이다.
NavLink
는 현재 라우트와 일치할 때 특별한 스타일이나 클래스를 적용할 수 있는 React Router의 컴포넌트다.
레이아웃의 자식 컴포넌트로 이런 설정을 추가하면 구성이 완료된다.
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<Layout />}>
<Route index element={<Index />} />
<Route path="/about" element={<About />}></Route>
<Route path="/products" element={<Products />}></Route>
</Route>
)
);
function App() {
return <RouterProvider router={router} />;
}
export default App;
이제 레이아웃 안에서 라우트 페이지가 제대로 표시되는 것을 확인할 수 있다.
외부 레이아웃 안에 서브 레이아웃이 필요한 상황은 자주 발생한다. 예를 들면, PRODUCTS 페이지에서는 카테고리를 선택할 수 있는 하위 메뉴가 있고, 해당 하위 메뉴를 선택하면 아래에 그 카테고리에 맞는 상품을 보여주는 구조가 필요할 수 있다. 이럴 때 중첩 라우팅을 통해 페이지를 유연하게 구성할 수 있다.
products 자식컴포넌트에 이렇게 또 중첩으로 레이아웃을 구성할수 있다.
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<Layout />}>
<Route index element={<Index />} />
<Route path="about" element={<About />}></Route>
<Route path="products" element={<Products />}>
<Route index element={<All />} />
<Route path="men" element={<Men />} />
<Route path="women" element={<Women />} />
</Route>
</Route>
)
);
Product 컴포넌트:
//porducts
import { Link, NavLink, Outlet, useMatch } from "react-router-dom";
function Products() {
const match = useMatch("/products");
return (
<div>
<nav>
<ul>
<li>
<Link to={""} className={match && "active"}>
All
</Link>
</li>
<li>
<NavLink to={"men"}>men</NavLink>
</li>
<li>
<NavLink to={"women"}>women</NavLink>
</li>
</ul>
</nav>
<div>
<Outlet />
</div>
</div>
);
}
export default Products;
서브 레이아웃에서 NavLink
가 원하는 대로 작동하지 않는 문제가 있다. 정확한 해결책은 아직 찾지 않았지만, 나는 그냥 Link
컴포넌트를 사용하고 useMatch
를 통해 URL을 판단한 뒤, active
클래스를 추가했다. 더 효율적인 해결 방법을 알고 있다면 댓글로 공유해주시면 감사하겠다!ㅜ
이제 화면에서 중첩 레이아웃을 구성한 것을 확인할 수 있다.
지금은 카테고리가 몇 개 없어서 문제가 없지만, 만약 카테고리가 많아진다면 일일이 컴포넌트를 만들어 Products
의 자식 컴포넌트로 추가하는 작업은 굉장히 번거로울 수 있다. 그런 상황에서 UI는 거의 동일하고 데이터만 다르다면, 동적 세그먼트를 사용할 수 있다. 여기서 path 안에 콜론(:)은 경로에서 "동적 세그먼트"로 변환하는 특별한 의미를 가진다.
<Route path="/" element={<Layout />}>
<Route index element={<Index />} />
<Route path="about" element={<About />}></Route>
<Route path="products" element={<Products />}>
<Route index element={<All />} />
<Route path=":categoriId" element={<categori />} />
</Route>
</Route>
여기서는 따로 동적 세그먼트와 동적으로 컴포넌트를 생성하는 방법에 대해서는 다루지 않을 것이다. 궁금한 분들은 공식 문서에서 자세한 정보를 찾아보는 것을 추천한다.