15 분 소요


1. react-router-dom 개요

1.1 react-router-dom 개념

  • 리액트 라우터(React Router)는 리액트 애플리케이션에서 페이지 이동을 구현할 수 있는 라이브러리이다.
  • 이를 통해 SPA(Single Page Application) 환경에서 URL에 따라 다른 컴포넌트를 렌더링할 수 있다.


1.2 react-router-dom 설치하기

vscode 터미널에서 아래 코드를 입력해서 패키지를 설치하자.

yarn add react-router-dom



2. react-router-dom 사용하기

2.1 페이지 컴포넌트 생성

여러개의 페이지를 이동하기 위해 가상의 페이지를 만들어보자.

src/pages에 Home, About, Contact, Works 총 4개의 컴포넌트를 만들어줬다.

특별한 내용이 없이 단순히 컴포넌트의 이름만 JSX에 넣어주었다.


② Router.jsx 생성 및 route 설정 코드 작성⭐

  • BrowserRouter를 Router로 감싸는 이유는, SPA의 장점인 브라우저 리로딩 없이 페이지 간 이동이 가능하도록 하기 위함이다.
  • path에다가 사용하고싶은 주소를 넣어주고, element에는 해당 주소로 이동했을 때 보여주고자 하는 컴포넌트를 넣어준다.
// src > shared > Router.jsx
import { BrowserRouter, Route, Routes, Navigate } from "react-router-dom";
import Home from "../pages/Home";
import About from "../pages/About";
import Contact from "../pages/Contact";
import Works from "../pages/Works";

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
        <Route path="contact" element={<Contact />} />
        {/* 사용자가 잘못된 경로로 이동했을 때 기본적으로 (/)로 리다이렉션 할 수 있다. */}
        <Route path="*" element={<Navigate replace to="/" />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;


2.1 App.jsx에 Router.jsx import 해주기

생성한 Router 컴포넌트를 아래 코드와 같이 App.jsx에 import 해준다.

import Router from "./shared/Router";

function App() {
  return <Router />;
}

export default App;


2.3 페이지 이동 테스트

페이지가 잘 이동하는지 확인해보자.

localhost:3000/home
localhost:3000/about;
localhost:3000/contact
localhost:3000/works

잘 이동한다!


3. 동적 라우팅(Dynamic Route)

3.1 동적 라우팅 개요

  • 동적 라우트에서는 경로에 따라 컴포넌트를 동적으로 할당하고, 경로의 일부를 매개변수로 사용하여 컴포넌트를 렌더링하는 것이 가능하다.
  • 즉, path에 유동적인 값을 넣어서 특정 페이지로 이동하게끔 할 수 있는 것이다.
  • 동적 라우트를 사용하면 /users/1, /users/2, /users/3과 같은 다양한 사용자 프로필을 동일한 컴포넌트로 처리할 수 있다.
const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        {/* 비효율적 */}
        <Route path="/" element={<Home />} />
        <Route path="/info/1" element={<Info />} />
        <Route path="/info/2" element={<Info />} />
        <Route path="/info/3" element={<Info />} />
      </Routes>
    </BrowserRouter>
  );
};

위 코드를 react-router-dom에서 지원하는 Dynamic Routes 기능을 이용해서 간결하게 동적으로 변하는 페이지를 처리해보자.


3.2 params 설정하기

useParams 이라는 훅을 사용하여 Route의 element에 넣어준 컴포넌트에서 parms 값을 가져올 수 있다.

  • useParams 은 path의 있는 id 값을 조회할 수 있게 해주는 훅이다.’
  • useParam을 이용하면 같은 컴포넌트를 렌더링하더라도 각각의 고유한 id 값을 조회할 수 있다.
<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/info/:id" element={<Info />} />
  </Routes>
</BrowserRouter>


3.3 params 받아오기

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

const Info = () => {
  const { id } = useParams(); // URL 파라미터에서 id값을 추출

  return <div>Info ID: {id}</div>;
};

export default Info;


3.4 응용(1) - params id를 활용한 상세 페이지 구현

“상세” 버튼을 클릭하면, 해당 아이템의 ID를 포함한 URL로 이동하여 Info 페이지에서 상세 정보를 볼 수 있도록 구현

<Link to={`info/${todo.id}`}>상세</Link>


3.5 응용(2) - id에 따른 조건부 렌더링

info.json

[
  {
    "id": 1,
    "title": "내가 제일 좋아하는 아이스크림은?",
    "content": "부라보콘 피스타치오 맛!!!🍦🍦"
  },
  {
    "id": 2,
    "title": "내가 제일 좋아하는 음식은?",
    "content": "돈가스!! 💰💰💲"
  }
]
import { useParams } from "react-router-dom";
import infoData from "../info.json";

const InfoPage = () => {
  const { id } = useParams();
  const infoFiltered = infoData.find((info) => info.id === parseInt(id));

  if (!infoFiltered) {
    return <div>정보를 찾을 수 없습니다.</div>;
  }

  return (
    <>
      <h1>InfoPage</h1>
      <ul>
        <li>{infoFiltered.title}</li>
        <li>{infoFiltered.content}</li>
      </ul>
    </>
  );
};

export default InfoPage;



4. Link 이동하기

4.1 useNavigate 사용하기(replace 옵션)

useNavigate 훅을 사용하면 코드 로직을 통해 페이지 이동을 제어할 수 있다.

즉, 어떤 버튼이나 컴포넌트를 눌렀을 때 페이지로 이동하게 만들기 위해 사용하는 훅이다.

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

const Home = () => {
  const navigate = useNavigate();

  return (
    <>
      <button onClick={() => navigate("/info")}>Info 페이지로 이동</button>
      <button onClick={() => navigate(1)}>앞으로 가기</button>
      <button onClick={() => navigate(-1)}>뒤로 가기</button>
    </>
  );
};

export default Home;


replace 옵션을 사용하여 특정 페이지로 이동할 때, 현재 페이지를 히스토리 스택에서 제거하고 새 페이지로 이동할 수 있다.

  • 사용자가 브라우저의 “뒤로 가기” 버튼을 눌렀을 때,
  • replace 옵션을 사용하면, 뒤로가기를 눌렀을 때 페이지 이동 기록이 초기화되어 삭제된 게시글의 상세 페이지로 돌아가는 것을 방지할 수 있다.
  • 즉, 스택을 초기화하므로 이전 페이지로 돌아가지 않게 한다.
<button onClick={() => navigate("/post-list", { replace: true })}>
  • 위 코드는 현재 페이지(게시글 상세 페이지)를 브라우저의 히스토리 스택에서 제거하고, /post-list 페이지를 히스토리 스택에 추가한다.
  • 이로 인해 사용자가 뒤로가기를 눌렀을 때 삭제된 게시글의 상세 페이지로 돌아가는 것을 방지할 수 있다.


4.2 Navigate vs useNavigate

Navigate는 컴포넌트 형태로 페이지를 이동할 때 사용된다. 렌더링 시 특정 경로로 즉시 리다이렉트 시킬 수 있다.

  • 보통 사용자가 특정 조건을 충족하지 않을 때 자동으로 다른 페이지로 리다이렉트하려는 경우 사용된다.
  • EX: 로그인 상태가 아닐 때 로그인 페이지로 리다이렉트
import { Navigate } from "react-router-dom";

function MyComponent() {
  const isLoggedIn = false;

  if (!isLoggedIn) {
    return <Navigate to="/login" />;
  }

  return <div>Welcome to the dashboard!</div>;
}


useNavigate는 훅(hook) 형태로 페이지를 프로그래밍 방식으로 이동시킬 수 있도록 해준다.

보통 버튼 클릭이나 폼 제출 등 이벤트 핸들러 내에서 호출된다.

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

function MyComponent() {
  const navigate = useNavigate();

  const handleClick = () => {
    navigate("/dashboard");
  };

  return <button onClick={handleClick}>Dashboard로 이동하기!</button>;
}


4.3 Navigate에서 state 사용하기

Navigate에서 state를 사용하면, 리다이렉트할 때 현재 경로와 같은 정보를 다음 페이지로 전달할 수 있다.

  • 특정 페이지로 이동할 때, 현재 위치나 기타 데이터를 전달하고 싶은 경우 state 속성을 사용할 수 있다.
  • 주로 사용자가 로그인 후 이전에 보려던 페이지로 리다이렉트시키고자 할 때 유용하다.
import { Navigate, useLocation } from "react-router-dom";

function ProtectedRoute() {
  const { isSignIn } = useAuth();
  const location = useLocation(); // 현재 페이지의 경로 정보를 가져옴

  if (!isSignIn) {
    return <Navigate to="/sign-in" state={{ from: location }} replace />;
  }

  return <Outlet />;
}


state=

  • state는 React Router에서 페이지를 이동할 때, 특정 상태나 데이터를 함께 전달하기 위해 사용된다.
  • state=는 현재 페이지(location)의 경로 정보를 state 객체의 from이라는 속성에 저장하여, 리다이렉트되는 페이지(/sign-in)로 전달한다.
  • 로그인 페이지에서 사용자가 로그인에 성공한 후 이전에 보려고 했던 페이지로 다시 리디렉션하는 경우에 유용하다.


replace

  • replace가 true로 설정되면, 현재 페이지를 히스토리 스택에서 대체하게 된다.
  • 즉, 브라우저의 뒤로 가기 버튼을 눌렀을 때, 리다이렉트 이전 페이지로 돌아가는 것이 아니라, 그 이전 페이지로 바로 돌아가게 된다.
  • 사용자가 특정 페이지로 리다이렉트되었을 때, 뒤로 가기 버튼을 눌러 리다이렉트 이전의 페이지로 돌아가지 않도록 하고 싶을 때 유용하다.


Link 는 html 태그중에 <a> 태그의 기능을 대체하는 API이다.

  • <a> 태그를 사용하면, 브라우저가 새로고침 되면 모든 컴포넌트가 다시 렌더링되야 하고, 우리가 리덕스나 useState를 통해 메모리상에 구축해놓은 모든 상태값이 초기화 되서 성능이 저하될 수 있다.
  • 따라서, Link 를 사용하여 SPA 환경에서 페이지 리로드 없이 라우트를 변경해야한다.
import { Link } from "react-router-dom";

const Home = () => {
  return (
    <nav>
      <Link to="/info">Info 페이지로 이동</Link>
    </nav>
  );
};

export default Home;


  • NavLink는 react-router-dom 라이브러리에서 제공하는 컴포넌트로, Link와 유사하게 사용되지만, 추가적으로 현재 경로와 매칭되었을 때 특정 스타일이나 클래스를 적용할 수 있는 기능을 제공한다.
  • 내비게이션 바나 메뉴에서 현재 활성화된 링크를 시각적으로 구분할 때 유용하다.
import { NavLink } from "react-router-dom";

const Navigation = () => {
  return (
    <nav>
      <NavLink
        to="/home"
        className={({ isActive }) => (isActive ? "active" : "")}
      >
        Home
      </NavLink>
      <NavLink
        to="/about"
        className={({ isActive }) => (isActive ? "active" : "")}
      >
        About
      </NavLink>
    </nav>
  );
};


아래와 같이 styled-components를 사용해서도 NavLink를 사용하여 현재 경로와 일치하는 경우 특정 스타일을 적용할 수 있다.

import { NavLink } from "react-router-dom";
import styled from "styled-components";

const Navigation = () => {
  return (
    <nav>
      <StyledNavLink to="/home">Home</StyledNavLink>
      <StyledNavLink to="/about">About</StyledNavLink>
      <StyledNavLink to="/contact">Contact</StyledNavLink>
    </nav>
  );
};

export default Navigation;

const StyledNavLink = styled(NavLink)`
  color: black;
  text-decoration: none;
  padding: 10px;

  &.active {
    color: red;
    font-weight: bold;
  }
`;



5. 중첩 라우트

5.1 중첩 라우트란?

중첩 라우트는 하나의 라우트 내부에 다른 라우트를 포함하는 구조이다.

  • 중첩 라우트를 사용하면 복잡한 UI 구조를 보다 명확하고 체계적으로 구성할 수 있다.
  • 예를 들어, 대시보드에 여러 섹션이 있는 경우, 각 섹션에 해당하는 라우트를 대시보드 라우트 내에 중첩하여 정의할 수 있다.
/* dashboard/profile 및 /dashboard/settings는 중첩 라우트. */
<Route path="/dashboard" element={<DashboardLayout />}>
  <Route path="profile" element={<Profile />} />
  <Route path="settings" element={<Settings />} />
</Route>


사용 예시

  • index 속성은 부모 경로(/)에 자동으로 렌더링되는 기본 하위 페이지를 설정한다. 이를 통해, 부모 경로에 접근했을 때 보여줄 기본 페이지를 지정할 수 있다.
  • 아래 코드에서 /dashboard 경로에 접근하면 Dashboard가 렌더링되고, 그 내부에 기본적으로 Overview가 표시된다.
<BrowserRouter>
  <Routes>
    <Route path="/" element={<Layout />}>
      <Route index element={<Home />} /> {/* 루트 경로에서 기본 페이지 */}
      <Route path="dashboard" element={<Dashboard />}>
        <Route index element={<Overview />} /> {/* 기본 대시보드 페이지 */}
        <Route path="profile" element={<Profile />} />
        <Route path="settings" element={<Settings />} />
      </Route>
      <Route path="about" element={<About />} />
    </Route>

    {/* 정의되지 않은 경로는 홈 페이지로 리다이렉트 */}
    <Route path="*" element={<Navigate replace to="/" />} />
  </Routes>
</BrowserRouter>

사용 사례

  • 검색 필터링: 사용자가 원하는 카테고리나 가격대에 맞는 제품을 필터링할 때
  • 페이지네이션: 페이지 번호를 쿼리 문자열로 관리하여 페이지를 전환할 때
  • 정렬 옵션: 정렬 기준을 URL에 쿼리 문자열로 추가하여 사용자가 선택한 정렬 옵션을 유지할 때


5.2 Outlet 컴포넌트

중첩된 라우트의 자식 컴포넌트를 렌더링하는 데 사용된다.

공통 레이아웃을 구현할 때 유용하다.

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Layout />}>
          <Route index element={<HomePage />} />
          <Route path="info" element={<InfoPage />} />
          <Route path="info/:id" element={<InfoDetailPage />} />
        </Route>

        <Route path="*" element={<Navigate replace to="/" />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;
// src/components/layouts/Layout.jsx
import { Outlet } from "react-router-dom";
import styled from "styled-components";
import Navbar from "./Navbar";

const Layout = () => {
  return (
    <StLayout>
      <StContainer>
        <Navbar />
        <Outlet /> {/* 여기에 자식 라우트 컴포넌트가 렌더링된다. */}
      </StContainer>
    </StLayout>
  );
};

export default Layout;

const StLayout = styled.main`
  width: 100%;
  height: 100vh;
`;

const StContainer = styled.div`
  width: 80%;
  background-color: #dfdfdf;
  margin: auto;
`;


아래와 같이 Outlet을 통해 특정 경로에 대해 로그인 여부를 확인하고, 로그인된 사용자만 해당 페이지에 접근할 수 있도록 설정할 수 있다.

import { BrowserRouter, Routes, Route } from "react-router-dom";
import Detail from "../pages/Detail";
import Home from "../pages/Home";
import Header from "../components/layouts/Header";
import Footer from "../components/layouts/Footer";
import AuthLayout from "./AuthLayout";
import Sample01 from "../pages/Sample01";
import Sample02 from "../pages/Sample02";

const Router = () => {
  return (
    <BrowserRouter>
      <Header />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/:id" element={<Detail />} />
        <Route element={<AuthLayout />}>
          <Route path="sample01" element={<Sample01 />} />
          <Route path="sample02" element={<Sample02 />} />
        </Route>

        <Route path="*" element={<Navigate replace to="/" />} />
      </Routes>
      <Footer />
    </BrowserRouter>
  );
};

export default Router;


// src/shared/AuthLayout.jsx
import { useEffect, useState } from "react";
import { Outlet, useNavigate } from "react-router-dom";

const AuthLayout = () => {
  const navigate = useNavigate();
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    // 로그인 여부를 체크
    if (!isLoggedIn) {
      navigate("/login");
    }
  }, [isLoggedIn]);

  return (
    <div>
      <Outlet />
    </div>
  );
};

export default AuthLayout;
  • AuthLayout 컴포넌트는 isLoggedIn이 true일 때 해당 경로에 맞는 컴포넌트를 Outlet을 통해 렌더링한다.
    • 따라서, http://localhost:3000/sample01 에서 Sample01만,
    • http://localhost:3000/sample02 에서 Sample02만 보이게 된다.



6. useSearchParams

6.1 useSearchParams란?

useSearchParams는 URL의 쿼리 문자열을 읽고, 수정하는 기능을 제공하는 훅이다.

  • 사용자에게 검색 필터링, 페이지네이션 등 다양한 검색 기능을 구현할 수 있다.
  • 쿼리 문자열은 URL의 ? 뒤에 오는 부분으로, 예를 들어 ?category=books&price=low와 같은 형식이다.
  • searchParams 객체는 URLSearchParams의 다양한 메서드(get, set, append, delete 등)를 지원한다.
import { useSearchParams } from "react-router-dom";

const SearchPage = () => {
  // searchParams: 현재 URL의 쿼리 파라미터를 나타내는 객체
  // setSearchParams: 쿼리 파라미터를 업데이트하는 함수
  const [searchParams, setSearchParams] = useSearchParams();

  // 쿼리 파라미터 읽기
  const paramValue = searchParams.get("paramName"); // paramName에 해당하는 값을 가져옴

  // 쿼리 파라미터 설정
  const updateSearchParams = () => {
    setSearchParams({ paramName: "newValue" }); // paramName의 값을 newValue로 설정
  };

  return (
    <div>
      <p>Parameter Value: {paramValue}</p>
      <button onClick={updateSearchParams}>Update Parameter</button>
    </div>
  );
};

export default SearchPage;


6.2 useSearchParams로 검색 기능 구현하기

useSearchParams는 쿼리 파라미터를 통해 URL에 상태를 유지하며 페이지 리로드 없이도 검색을 구현할 수 있는 장점이 있다.

// info.json
[
  {
    id: 1,
    title: "내가 제일 좋아하는 아이스크림은?",
    content: "부라보콘 피스타치오 맛!!!🍦🍦",
  },
  {
    id: 2,
    title: "내가 제일 좋아하는 음식은?",
    content: "돈가스!! 💰💰💲",
  },
  {
    id: 3,
    title: "테스트",
    content: "A B C d e f",
  },
];
// src/pages/InfoPage.jsx
import { useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
import dummyData from "../../../src/dummy";

const Search = () => {
  const [searchParams, setSearchParams] = useSearchParams(); // 쿼리 파라미터 상태

  /* searchParams.get("search")을 초기 상태로 넣어주는 이유?
    사용자가 페이지를 새로 고침하거나 URL을 직접 입력했을 때 검색 쿼리 파라미터를 기억하기 위함! */
  const [query, setQuery] = useState(searchParams.get("search") || ""); // 검색 쿼리 상태
  const [filteredData, setFilteredData] = useState(dummyData); // 필터링된 데이터 상태

  // 검색 버튼 클릭 시 검색어를 URL 쿼리 파라미터로 설정
  const handleSearch = (e) => {
    e.preventDefault(); // 폼 제출 시 페이지 리로드 방지
    const trimmedQuery = query.trim().toLowerCase(); // 검색어의 공백 제거
    setSearchParams({ search: trimmedQuery }); // 쿼리 파라미터 업데이트
  };

  // 검색어가 변경될 때 필터링된 데이터 업데이트
  useEffect(() => {
    const trimmedParams =
      searchParams.get("search")?.trim().toLowerCase() || "";

    if (trimmedParams) {
      const filteredDummy = dummyData.filter(
        (dummy) =>
          dummy.title.toLowerCase().includes(trimmedParams) ||
          dummy.content.toLowerCase().includes(trimmedParams)
      );
      setFilteredData(filteredDummy);
    } else {
      setFilteredData(dummyData); // 검색어가 공백만 있는 경우 전체 데이터 표시
    }
  }, [searchParams]); // searchParams가 변경될 때마다 호출됨

  return (
    <>
      <form onSubmit={handleSearch}>
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="검색어를 입력하세요."
        />
        <button type="submit">검색하기</button>
      </form>
      <div>
        {filteredData.length > 0 ? (
          filteredData.map((dummy) => (
            <ul key={dummy.key}>
              <li>{dummy.title}</li>
              <li>{dummy.content}</li>
            </ul>
          ))
        ) : (
          <p>검색 결과가 없습니다.</p>
        )}
      </div>
    </>
  );
};

export default Search;
  • searchParams.get("query")
    • URL에서 query라는 이름의 쿼리 파라미터를 가져온다.
    • 예를 들어, URL이 http://example.com/search?query=apple 이면 searchParams.get(“query”)는 “apple”을 반환한다.
    • 쿼리 파라미터가 없다면 null을 반환하므로 query 변수는 빈 문자열로 설정된다.



7. useLocation로 페이지 정보 얻기

react-router-dom을 사용하면, 현재 위치하고 있는 페이지의 여러가지 정보를 추가적으로 얻을 수 있다.

이 정보들을 이용해서 페이지 안에서 조건부 렌더링에 사용하는 등, 여러가지 용도로 활용할 수 있다.

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

const HomePage = () => {
  const location = useLocation();
  console.log("location: ", location);

  return <div>{`현재 페이지 : ${location.pathname.slice(1)}`}</div>;
};

export default HomePage;



8. React Router v6.4+

8.1 RouterProvider

라우터의 컨텍스트를 React 애플리케이션에 제공하는 컴포넌트이다.

RouterProvider는 createBrowserRouter로 생성한 라우터 객체를 router prop으로 받아서 라우팅을 설정한다.


방법 1: 최상단에 browserRouter로 감싸기

// src/App.js
import { RouterProvider } from "react-router-dom";
import router from "./router"; // 라우터 설정 import

function App() {
  return <RouterProvider router={router} />;
}

export default App;


방법 2(추천):RouterProvider를 import해서 router를 제공하기

import {
  createBrowserRouter,
  RouterProvider,
  Navigate,
} from "react-router-dom";
import PostListPage from "pages/public/PostListPage";
import SignupPage from "pages/public/SignupPage";
import MyPage from "pages/protected/MyPage";
import SigninPage from "pages/public/SigninPage";
import PostDetailPage from "pages/public/PostDetailPage";
import PostFormPage from "pages/public/PostFormPage";
import { useAuth } from "context/AuthContext";
import Layout from "components/layouts/Layout";
import UserProfilePage from "pages/public/UserProfilePage";
import PublicHomePage from "pages/public/PublicHomePage";
import ProtectedRoute from "./ProtectedRoute";

const Router = () => {
  const { isSignIn } = useAuth();

  // 공통 라우트 설정
  const commonRoutes = [
    { path: "/", element: <PublicHomePage /> }, // 모든 사용자에게 기본 페이지로 제공
    { path: "/post-list", element: <PostListPage /> },
    { path: "/posts/:id", element: <PostDetailPage /> },
    { path: "/user-profile", element: <UserProfilePage /> },
  ];

  // 라우터 설정
  const router = createBrowserRouter([
    {
      path: "/",
      element: <Layout />, // 모든 라우트의 상위 컴포넌트로 Layout 설정
      children: [
        ...commonRoutes, // 공통 라우트 추가
      ],
    },
    notFound,
  ]);

  return <RouterProvider router={router} />;
};

export default Router;


8.2 createBrowserRouter

React 애플리케이션에서 브라우저 기반의 라우팅을 설정하기 위한 함수이다. 라우트 설정을 기반으로 라우터 객체를 반환한다.

일반적으로 createBrowserRouter는 라우터를 구성하고 RouterProvider에 전달하기 위해 사용된다.

import { createBrowserRouter } from "react-router-dom";
import Home from "./Home";
import About from "./About";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Home />,
  },
  {
    path: "/about",
    element: <About />,
  },
]);

export default router;


8.3 routes

routes는 Route 객체를 요소로 가지는 배열이다. 이 배열은 여러 개의 Route 객체를 포함할 수 있으며, 이러한 객체들은 children 속성을 통해 연결된다.

import { createBrowserRouter, Outlet } from "react-router-dom";
import MainPage from "./MainPage";
import Products from "./Products";
import ProductDetail from "./ProductDetail";
import Contact from "./Contact";

// 라우터 설정
const router = createBrowserRouter([
  {
    path: "/",
    element: (
      <div>
        <p>메인 페이지</p>
        <Outlet />
      </div>
    ),
    children: [
      {
        // 제품 목록 페이지
        path: "products",
        element: <Products />,
        children: [
          {
            // 특정 제품 상세 페이지
            path: ":products/:productsId",
            element: <ProductDetail />,
          },
        ],
      },
      {
        // 연락처 페이지
        path: "contact",
        element: <Contact />,
      },
    ],
  },
]);

export default router;


8.4 Route Object

Route Object는 각 라우트를 정의하는 객체이다. 이 객체는 라우팅을 설정하는 데 필요한 다양한 속성을 포함하고 있다.

interface RouteObject {
  path?: string;
  index?: boolean;
  children?: React.ReactNode;
  caseSensitive?: boolean;
  id?: string;
  loader?: LoaderFunction;
  action?: ActionFunction;
  element?: React.ReactNode | null;
  Component?: React.ComponentType | null;
  errorElement?: React.ReactNode | null;
  ErrorBoundary?: React.ComponentType | null;
  handle?: RouteObject["handle"];
  shouldRevalidate?: ShouldRevalidateFunction;
  lazy?: LazyRouteFunction<RouteObject>;
}
속성 설명
path 라우트가 매칭될 URL 경로를 정의한다.
index 부모 라우트의 기본 자식 라우트를 정의한다. true로 설정하면 자식 라우트가 기본 경로로 간주된다.
children 중첩된 자식 라우트를 정의할 수 있는 배열이다. 부모 라우트 아래에 자식 라우트를 설정할 때 사용된다.
caseSensitive 경로 매칭에서 대소문자를 구분할지 여부를 설정한다.
id 라우트의 고유 식별자를 설정한다.
loader (선택 사항) 해당 라우트에 필요한 데이터를 로드하기 위한 비동기 함수이다. 데이터가 로드된 후 컴포넌트가 렌더링된다.
action (선택 사항) 해당 라우트에서 발생하는 POST 요청 등을 처리하기 위한 함수이다.
element 해당 경로에 렌더링할 React 컴포넌트를 지정한다.
Component (선택 사항) element와 유사하게, 해당 경로에 렌더링할 React 컴포넌트를 지정한다. (구버전 React Router에서 사용됨)
errorElement (선택 사항) 해당 경로에서 에러가 발생했을 때 렌더링할 컴포넌트를 지정한다.
ErrorBoundary (선택 사항) 에러 경계 컴포넌트를 지정한다. 이 컴포넌트는 자식 라우트에서 에러가 발생했을 때 사용된다.
handle (선택 사항) 라우트에 관련된 메타데이터를 설정할 수 있는 객체이다.
shouldRevalidate (선택 사항) 해당 라우트의 데이터가 재검증되어야 하는지 여부를 결정하는 함수이다.
lazy (선택 사항) 라우트의 컴포넌트를 지연 로딩하기 위한 함수이다.
   
import { createBrowserRouter, RouterProvider, Outlet } from "react-router-dom";
import Home from "./Home";
import About from "./About";
import Profile from "./Profile";
import ErrorPage from "./ErrorPage";
import ErrorBoundaryComponent from "./ErrorBoundaryComponent";
import { fetchData } from "./api";

// 라우터 설정
const router = createBrowserRouter([
  {
    // 루트 경로
    path: "/",
    element: (
      <div>
        <header>메인 페이지</header>
        <Outlet />
      </div>
    ),
    // 기본 자식 라우트
    index: true,
    // 중첩된 자식 라우트
    children: [
      {
        path: "home",
        element: <Home />,
        // 비동기 데이터 로딩
        loader: async () => {
          const data = await fetchData("/home");
          return { data };
        },
        // POST 요청 처리
        action: async ({ request }) => {
          const formData = new FormData(request.body);
          // 처리 로직
        },
        // 경로 매칭 대소문자 구분
        caseSensitive: true,
        // 에러가 발생했을 때 렌더링할 컴포넌트
        errorElement: <ErrorPage />,
        // 에러 경계 컴포넌트
        ErrorBoundary: ErrorBoundaryComponent,
        // 메타데이터 설정
        handle: { title: "Home Page" },
        // 데이터 재검증 여부 결정 함수
        shouldRevalidate: () => true,
        // 컴포넌트 지연 로딩
        lazy: () => import("./Home"),
      },
      {
        path: "about",
        element: <About />,
      },
      {
        path: "profile/:userId",
        element: <Profile />,
      },
    ],
  },
]);

export default function App() {
  return <RouterProvider router={router} />;
}


8.5 Layout Route

Layout Route은 애플리케이션의 기본 레이아웃을 정의하는 데 사용된다. path를 생략하게 된다면 이는 단지 UI layout를 위한 route가 되는 것이다.

// 라우터 설정
const router = createBrowserRouter([
  {
    // 메인 레이아웃 라우트
    element: <MainLayout />,
    children: [
      {
        // 홈 페이지
        path: "home",
        // 기본 경로, 기본적으로 렌더링될 컴포넌트
        index: true,
        element: <Home />,
      },
      {
        // 어바웃 페이지
        path: "about",
        element: <About />,
      },
      {
        // 사용자 프로필 페이지
        path: "profile/:userId",
        element: <Profile />,
      },
    ],
  },
  {
    // 관리자 레이아웃 라우트
    element: <AdminLayout />,
    children: [
      {
        // 대시보드 페이지
        path: "dashboard",
        index: true,
        element: <Dashboard />,
      },
      {
        // 설정 페이지
        path: "settings",
        element: <Settings />,
      },
    ],
  },
  {
    // 모든 에러를 처리할 에러 페이지
    path: "*",
    element: <ErrorPage />,
  },
]);


카테고리:

업데이트:

댓글남기기