본문 바로가기
React

[React] react-router v7+

by mtm1018 2025. 8. 13.

지난 라우터 관련글은 6버전이기도하고 이번에 새로 부트캠프에서 배운 라우터 내용을 정리하고자

리액트 라우터 공식사이트를 보며 정리해보는 글.

https://reactrouter.com/home

[React Router Home | React Router

reactrouter.com](https://reactrouter.com/home)

Declarative Mode

직역하자면 선언형 모드이다.

Routing
<Routes>
  <Route index element={<Home />} />
  <Route path="about" element={<About />} />

  <Route element={<AuthLayout />}>
    <Route path="login" element={<Login />} />
    <Route path="register" element={<Register />} />
  </Route>

  <Route path="concerts">
    <Route index element={<ConcertsHome />} />
    <Route path=":city" element={<City />} />
    <Route path="trending" element={<Trending />} />
  </Route>
</Routes>

중첩라우팅방식을 설명하는 코드이다.

Outlet을 통해 부모 라우트가 렌더하는 위치에 자식 라우트가 들어갈 자리를 선정할 수 있다.

이 때, index는 Outlet에 렌더되는 가장 디폴트 페이지를 뜻한다.

또한, index가 되는 페이지의 경우 자식 라우트를 가질 수 없다.

이건 index의 경우 하나의 페이지라는 개념보다는 부모의 Outlet에 들어갈 기본화면 역할이라서 그러하다.

path경로 앞에 :을 붙이는걸 동적 세그먼트라고 하는데

동적세그먼트를 사용시 URL 파라미터를 참고 하여 동적으로 path값을 변경할 수 있다

<Route path="projects">
  <Route index element={<ProjectsHome />} />
  <Route element={<ProjectsLayout />}>
    <Route path=":pid" element={<Project />} />
    <Route path=":pid/edit" element={<EditProject />} />
  </Route>
</Route>

위 예시는 Route Prefixes이다. 부모의 path="projects"가 자식 라우트 경로의 prefix가 된다.

모든 엔드포인트 앞에 부모의 path를 붙여 부모 path의 경로란 것을 표시 할 수 있다.

import { NavLink, Link } from "react-router";

function Header() {
  return (
    <nav>
      <NavLink
        to="/"
        className={({ isActive }) =>
          isActive ? "active" : ""
        }
      >
        Home
      </NavLink>

      <Link to="/concerts/salt-lake-city">Concerts</Link>
    </nav>
  );
}

그런데 라우팅을 무조건 Route태그를 통해 할 필요는 없다.

Link태그라는것도 있는데 기본 HTML에서 사용하는 a태그를 생각해보면 역할의 짐작이 가능할 것이다.

하지만 NavLink라면 얘기가 약간은 다르다.


Navigate

가끔 웹 페이지를 이용하다보면 내가 어떤 메뉴를 클릭했는지 알 수있게 gnb나 llnb에서 표시해주는 기능읋 많이 보았을 것이다.

NavLink는 위와 같은 기능을 사용할 시 클래스라던가 스타일을 입혀 사용자가 어떤것을 눌렀는지

활성화 상태를 표시할 수 있게 만들어준다.

// children
<NavLink to="/message">
  {({ isActive }) => (
    <span className={isActive ? "active" : ""}>
      {isActive ? "👉" : ""} Tasks
    </span>
  )}
</NavLink>

<Children 노드에도 적용시킬 수 있는 모습>


import { useNavigate } from "react-router";

export function LoginPage() {
  let navigate = useNavigate();

  return (
    <>
      <MyHeader />
      <MyLoginForm
        onSuccess={() => {
          navigate("/dashboard");
        }}
      />
      <MyFooter />
    </>
  );
}

위 코드는 useNavigate()훅을 이용하여 강제로 사용자를 특정 페이지로 이동시킬 수있다.

react-router 공식 문서에 따르면 사용하기 좋은 상황의 예를 들어놨는데 그대로 옮기자면 이렇다

  • 폼 제출 성공시
  • 사용자가 페이지에 오랫동안 머물러있지만 아무 활동이 없을 때
  • 시간제한이 있는 UI

이 때, 리액트가 관리하는 useLocation훅을 사용해 사용자가 방문한 마지막 페이지로 이동시켜 줄 수 있다.

// useLocation 훅에서 관리하는 주요 속성

  pathname: "/products/123", // 현재 경로(쿼리, 해시 제외)
  search: "?category=shoes&sort=price", // URL 쿼리스트링
  hash: "#reviews", // 해시(anchor)
  state: { from: "/login" }, // navigate()로 보낸 추가 데이터
  key: "abc123" // React Router에서 내부적으로 쓰는 고유 키

Data Mode

데이터 모드는 선언형모드에서의 문제점을 개선한 모드이다

선언형 모드의 문제점은 다음과 같다

  1. 데이터 로딩타이밍이 제각각이다
    • 컴포넌트단에서 useEffect로 데이터를 불러오다보니 페이지 전환 후 로딩이 시작되기 때문에 화면이 깜빡거리는 문제점이 생김

로딩상태 중복관리

  • 페이지가 로딩되는 상태와 상태관리 코드가 중복해서 적히는 문제점이 있었다.

그러면서 새로운 문법들도 추가 되었다.


Routing

데이터 모드에서 라우터를 만들 때 <Routes></Routes>가 아닌 createBrowserRouter([]) 를 사용하게 되는 데,

 

이 함수안에 들어가는 라우트 정보들은 path컴포넌트가 필수적으로 들어가야한다.

 

추가적으로 더 많은 객체 속성들이 있다.라우트의 정보들을 객체배열로 정의해서 createBrowserRouter로 전달하게된다.

import {
  createBrowserRouter,
  useLoaderData,
} from "react-router";

createBrowserRouter([
  {
    path: "/teams/:teamId",
    loader: async ({ params }) => {
      let team = await fetchTeam(params.teamId);
      return { name: team.name };
    },
    Component: Team,
  },
]);

function Team() {
  let data = useLoaderData();
  return <h1>{data.name}</h1>;
}

 

추가적으로 중첩 라우팅 같은 효과를 내려면 children 배열 안에 담아 관리할 수 있다.

createBrowserRouter([
  {
    path: "/dashboard",
    Component: Dashboard,
    children: [
      { index: true, Component: Home },
      { path: "settings", Component: Settings },
    ],
  },
]);

 

 

Layout Routes처럼 path경로가 없이 라우팅을 시킬 수도 있다

createBrowserRouter([  
{  
    Component: MarketingLayout,  
    children: [  
    { index: true, Component: Home },  
    { path: "contact", Component: Contact },  
    ],  
},

 

이런 라우팅은 이름그대로 레이아웃만을 위한 라우팅으로 사용한다.

 

이 때, 해당 레이아웃 컴포넌트에는 Outlet을 붙여서 자식컴포넌트가 어디에 보일지 표시를 해두어야한다.

 

혹은 컴포넌트없이 prefix만 하고싶은 경우에는 반대로 컴포넌트를 빼고 path만 넣으면 된다.


Route Object

앞서 데이터모드에서는 createBrowserRouter안에 라우트 정보가 전달된다고 썼는데

 

여기서 들어가는 것을 라우트 객체라 부른다.

 

이때 객체안에 들어갈 수 있는 다른 속성들은 뭐가 있을까?

 

 

 

loader

 

useEffect훅과 같은 역할을 한다

 

다른점은 라우트 컴포넌트가 렌더링 되기 전에 정보를 불러온다는 점이다.

import {
  useLoaderData,
  createBrowserRouter,
} from "react-router";

createBrowserRouter([
  {
    path: "/",
    loader: loader,
    Component: MyRoute,
  },
]);

async function loader({ params }) {
  return { message: "Hello, world!" };
}

function MyRoute() {
  let data = useLoaderData();
  return <h1>{data.message}</h1>;
}

 

만약 타입스크립트를 사용하고 있다면 해당 파라미터가 오는 자리에 LoaderFunctionArgs를 사용할 수 있는데

 

LoaderFunctionArgs의 타입은 이렇게 정의되어있다.

 

interface LoaderFunctionArgs {  
context: Context;  
params: Params;  
request: Request;  
}

 

이를 통해 loader의 매개변수로 커스텀 컨텍스트와 파라미터,

 

그리고 서버에게 요청하는 객체 (쿼리, 쿠키등)까지 넣을 수 있다는 것을 알 수 있다.

 

loader로 불러온 데이터는 useLoaderData() 를 사용해 값을 가져올 수 있다.

 

 

action

 

action은 서버쪽 데이터를 변경할 수 있게한다(수정, 삭제)

 

그리고 action이 실행되면 현재 페이지의 모든 loader데이터가 자동으로 재 검증 된다.

 

공식페이지에서 설명하기로는 useFetcher()나 useSubmit()훅 을 사용될때 불러와진다고 한다.

 

즉, 폼 전송이나 서버로 데이터를 요청할 때 발동된다.

 

createBrowserRouter([  
{  
    path: "/items",  
    action: action,  
    loader: loader,  
    Component: Items,  
},  
]);

async function action({ request }) {  
    const data = await request.formData();  
    const todo = await fakeDb.addItem({  
    title: data.get("title"),  
  });  
    return { ok: true };  
}

 

lazy

 

프로그래밍에서 lazy가 가지는 뜻은 지연 로딩을 가능하게 해준다는 뜻으로

 

코드나 페이지가 필요할때만 불러오는 기능이다

createBrowserRouter([  
{  
    path: "/app",  
    lazy: async () => {  
    const [Component, loader] = await Promise.all(\[  
    import("./app"),  
    import("./app-loader"),  
    ]);  
  return { Component, loader };  
    },
  },  
]);

 

 

'React' 카테고리의 다른 글

[React] TanStack-query  (0) 2025.09.09
[React] Zustand  (4) 2025.08.26
[React] 렌더링 스냅샷과 업데이트  (0) 2025.07.15
[React] sideEffect  (0) 2025.07.09
[React] 리액트가 렌더링 하는 방법  (1) 2025.07.06