Router v6 Nested Routes

homewiz·2024년 4월 4일

React & typescript

목록 보기
9/18
post-thumbnail

1. intro

중첩 라우팅 하는 법에 대해 소개한다.

2. How to handle nested routes

중첩 라우팅은 쉽게 말해 route page 안에 route page를 넣어 필요한부분만 갱신하는 방식이다.

GNB
 |– Category Link 1 – Sub Navigation Bar (Menu)
   |– Page Link 1
   |– Page Link 2
 |– Category Link 2 – Sub Navigation Bar (Menu)
   |– Page Link 1
   |– Page Link 2

Category1 page에서 하위 페이지를 이동 하는 경우 Outlet component를 이용해 Page가 랜더링된다.

3. Create Routes

mkdir ./src/pages/Category4
touch ./src/pages/Category4/index.tsx
touch ./src/pages/Category4/Category4Page1.tsx
touch ./src/pages/Category4/Category4Page2.tsx

@/pages/Category4/Page1.tsx

import React from "react";

import { useLocation } from "react-router-dom";

const Category4Page1 = () => {
  const location = useLocation();
  return <span>This page : {location.pathname}</span>;
};

export default Category4Page1;

@/pages/Category1/Category4Page2.tsx

import Category4Page1 from "./Category4Page1";

const Category4Page2 = Category4Page1;

export default Category4Page2;
  • 같은 소스이므로 상속처럼 사용 한다.(상속 절대 아님XXX)

@/pages/Category4/index.tsx

import React from "react";

import { Outlet, useLocation } from "react-router-dom";

const Category4 = () => {
  const location = useLocation();
  return (
    <>
      <div>This {location.pathname}</div>
      {/* Outlet를 통해 컴포넌트에 하위 route들이 랜더링 된다. */}
      <Outlet />
    </>
  );
};

export default Category4;

@/App.tsx

import React from "react";
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";

import GNB from "@/components/Navigations/GNB";
import Category2 from "@/pages/Category2";
import Category3 from "@/pages/Category3";
import Dashboard from "@/pages/Dashboard";
import NotFound from "@/pages/NotFound";
import Category4 from "./pages/Category4";
import Category4Page1 from "./pages/Category4/Category4Page1";
import Category4Page2 from "./pages/Category4/Category4Page2";

function App() {
  return (
    <div className="p-6">
      <Router>
        <GNB />
        <Routes>
          <Route path="/" element={<Dashboard />} />
          <Route path="/category2" element={<Category2 />} />
          <Route path="/category3" element={<Category3 />} />
          <Route path="/category4" element={<Category4 />}>
            {/* /category1 경로 */}
            <Route index element={<Category4Page1 />} />
            {/* /category1/page1 경로 */}
            <Route path="/category4/page1" element={<Category4Page1 />} />
            <Route path="/category4/page2" element={<Category4Page2 />} />
          </Route>
          <Route path="*" element={<NotFound />} />
        </Routes>
      </Router>
    </div>
  );
}

export default App;
  • localhost:3000/category4 =>Category4과 하위 Page1 출력

주의사항

// error code
<Route path="/page2" element={<Page2 />} />
// good 
<Route path="/category4/page2" element={<Page2 />} />

* 하위 route의 path는 반드시 상위 path를 같이 기재 해줘야 한다.
Uncaught runtime errors:
ERROR
Absolute route path "/page2" nested under path "/category4" is not valid. An absolute child route path must start with the combined path of all its parent routes.

4.하위 메뉴 구현

./src/pages/Category4/index.tsx

import React from "react";
import { Link, Outlet, useLocation } from "react-router-dom";

const Category4 = () => {
  const location = useLocation();
  return (
    <>
      <div className="bg-slate-200 space-x-4 p-2 font-bold text-black">
        <Link to={`/category4/page1`}>Page1</Link>
        <Link to={`/category4/page2`}>Page2</Link>
      </div>
      <div>This {location.pathname}</div>
      {/* Outlet를 통해 컴포넌트에 하위 route들이 랜더링 된다. */}
      <Outlet />
    </>
  );
};

export default Category4;
  • page1, page2를 눌러 변경을 확인하자.

5. Reference

https://blog.logrocket.com/react-router-v6-guide/

Tip. 새로고침 에러

http://localhost:3000/category1/page2 이처럼 2depth 이하의 페이지에서 새로고침을 할경우
페이지 랜더링이 안되고 F12 콘솔창에 아래와 같이 에러 메세지가 발생한다면
webpack > output > publicpath 설정을 해줘야 한다.

Failed to load resource: the server responded with a status of 404 (Not Found)
page3:1 Refused to execute script from 'http://localhost:3000/category2/main.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.

output: {
  + publicPath: "/",
  path: path.join(__dirname, "/dist"),
  filename: "main.js",
  clean: true
},

0개의 댓글