TECH

react-router-dom v6

ssund 2023. 3. 2. 22:48

Routing

사용자가 요청한 URL에 따라 알맞는 페이지를 보여주는 것

React Router

링크를 눌러서 다른페이지로 이동하게 될 때 서버에 다른페이지의 Html을 새로 요청하는 것이 아니라

브라우저의 History API를 사용하여 브라우저의 주소창의 값만 변경하고

기존페이지에 웹 애플리케이션을 유지하면서 라우팅 설정에 따라 또 다른 페이지를 보여준다.

설치

npm i react-router-dom


BrowserRouter

BrowserRouter컴포넌트로 최상위 컴포넌트를 감싸준다.

//src/index.js

import App from "./App";
import { BrowserRouter } from "react-router-dom";
import React from "react";
import ReactDOM from "react-dom/client";

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
    <BrowserRouter>
      <App />
    </BrowserRouter>
);


createBrowerRouter

path, element, children(중첩라우팅) 설정 가능하다.

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

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

export default router;

 

RouterProvider로 감싸주고 router props로 router를 내려줘야한다. 

// index.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "react-router-dom";
import router from "./Router";

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

 

중첩라우팅 시 하위컴포넌트가 보여질 영역에 Outlet을 선언해준다. 

// Root
import { Outlet } from "react-router-dom";

function Root() {
  return (
    <div>
      header
      <Outlet />
    </div>
  );
}

export default Root;



Routes, Route

경로에 따라 원하는 컴포넌트를 보여줄 수 있다.

Route는 Routes 내부에서 사용되어야한다.

<Routes>
    <Route path="/경로" element={컴포넌트} />
  <Route path="/경로" element={컴포넌트} />
</Routes>


Link

다른페이지로 이동하는 링크

a태그를 사용해서 이동하면 페이지가 새로 로드가 된다.

Link를 사용하면 페이지를 새로 불러오는 것을 막고 History API를 통해 브라우저 주소의 경로만 변경해준다.

<Link to="/경로">링크 이름</Link>

to props로 객체를 넣어줄 수도 있다.

state props는 페이지 이동시 값을 전달하는 것. useLocation으로 접근할 수 있다.

 <Link
   to={{
   pathname: path,
   search: "?search=nike",
   hash: "#111",
   }}
   state={{ isDark: true }}
 >
 {label}
 </Link>


URL 파라미터와 쿼리스트링

URL 파라미터 : Profile/velopert

쿼리스트링: search?q="nike"

URL파라미터는 특정데이터를 조회할때 사용
쿼리스트링은 검색페이지, 페이지네이션, 정렬 데이터조회에 많이 사용된다.

useParams (URL 파라미터)

Route에서 파라미터 키(username)로 받을 값을 넣어준다.

// router.tsx

<Routes>
  <Route path="/profile/:username" element={<Profile />}></Route>
</Routes>

useParams hook을 사용하여
route에서 설정해 준(username) 파라미터 값을 가져올 수 있다.

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

const Profile = () => {
  const { username } = useParams();

  return <div>이름: {username}</div>;
};

export default Profile;


useLocation (쿼리스트링)

useLocation hook을 사용해서 location 객체를 가져올 수있다.

쿼리스트링 경우 location.search를 사용해 조회할 수있다.

// page1.tsx

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

const Page1 = () => {
  const location = useLocation();

  console.log(location);
};

export default Page1;

/page1?p=1&searh=nike 로 접근한 경우

 

Hash: 해시값을 받아온다.
/page1?p=1&searh=nike#11 로 접근한 경우 #11

Key: location 객체의 고유값, 초기 default 페이지가 변경될 때마다 고유의 값 생성

pathname: 현재 경로 (쿼리스트링, 해시값 제외)

search: 쿼리스트링 값

state: 페이지 이동시 임의로 넣을 수있는 상태 값


useSearchParams (쿼리스트링 파싱)

?search=nike 처럼 키와 값으로 이루어진 쿼리스트링은 파싱하는 작업을 거치고 사용을 해야했는데

v6부터 useSearchParams hook을 사용해서 쉽게 파싱할 수 있다.

useSearchParams가 제공하는 get함수를 사용해서 쿼리값을 가져올 수있다.
modifier에 object형태로 작성을 하면 쿼리스트링값을 편하게 변경할 수 있다.

쿼리파라미터가 없는경우는 null

쿼리파라미터 값은 모두 string이다

// /page1?search=nike&page=2#111 

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

const Page1 = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  const search = searchParams.get("search"); //nike
  const page = searchParams.get("page"); //2

  const goToNextPage = () => {
    setSearchParams({ page: "3", search: "jordan" }); ///page3?search=jordan&page=2#111  
  };

  return (
    <div>
      <button onClick={goToNextPage}>page +</button>
    </div>
  );
};

export default Page1;

 

useMatch()

location이 useMatch 매개변수와 동일한 경우 object리턴, 동일하지 않는경우 null

 


중첩라우트

라우트 안에 라우트가 있는 형태. 게시글 리스트 > 게시글 상세

// router.ts
<Routes>
  <Route path="/board" element={<Board />}></Route>
  <Route path="/board/:id" element={<BoardDetail />}></Route>
</Routes>


outlet

outlet을 이용해서 공통레이아웃을 표현할 수있다.

게시글 페이지 마다 게시글 메뉴가 표시되어야하는 경우

하위에 있는 route 컴포넌트가 outlet 컴포넌트 영역에 보여지게 된다.

// router.ts
<Routes>
  <Route path="/board" element={<Board />}>
        <Route path=":id" element={<BoardDetail />}></Route>
    </Route>
</Routes>
// board
import { Link, Outlet } from 'react-router-dom';

const Board = () => {
  return (
    <div>
      <Outlet /> // BoardDetail 컴포넌트가 표시된다. 
      <ul>
        <li>
          <Link to="1">게시글 1</Link>
        </li>
        <li>
          <Link to="2">게시글 2</Link>
        </li>
        <li>
          <Link to="3">게시글 3</Link>
        </li>
      </ul>
    </div>
  );
};

export default Board;

헤더, 푸터, 사이드바 공통으로 들어가는 레이아웃이 있는경우 outlet을 사용해서 쉽게 표현할 수 있다.

1. outlet을 가지고 있는 공통컴포넌트 layout을 만든다. 

// layout.tsx
import Gnb from "./components/layout/Gnb";
import Header from "./components/layout/Header";
import { Outlet } from "react-router-dom";

const Layout = () => {
  return (
    <>
      <Header />
      <Gnb />
      <main>
        <Outlet />
      </main>
    </>
  );
};

export default Layout;

2. route에 공통 컴포넌트를 사용할 컴포넌트를 layout 하위 route로 넣어준다. 

<Routes>
  // 공통 컴포넌트를 사용할 페이지 
  <Route element={<Layout />}>
    <Route path="/" element={<Main />}></Route>
    <Route path="/page1" element={<Page1 />}></Route>
    <Route path="/page2" element={<Page2 />}></Route>
    <Route path="/board/:id" element={<BoardDetail />}></Route>
  </Route>
  // 공통 컴포넌트를 사용하지 않는 페이지
  <Route path="/login" element={<Login />}></Route>
  <Route path="*" element={<NotFound />}></Route>
</Routes>


layout 파일에 outlet영역에 하위 라우터로 선언한 컴포넌트가 그려진다!

 

useOutletContext

outlet에 들어가는 하위컴포넌트로 데이터를 넘겨야할경우 사용

link에 state를 넣어서 전달하는 방법도 있지만 link state를 사용하는 경우 url에 바로 접속하는 경우 데이터를 못가져온다. 

// /user
import { Link, Outlet } from "react-router-dom";

const User = () => {
  return (
    <div>
      <Link to="detail"> 디테일 </Link>
      <Outlet
        context={{
          theme: "dark",
        }}
      />
    </div>
  );
};

export default User;
// /user/detail

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

interface IDetail {
  theme: string;
}

const Detail = () => {
  const { theme } = useOutletContext<IContext>();
  return <div>Detail theme: {theme}</div>;
};

export default Detail;

 

useNavigate

Link를 사용하지 않고 다른페이지로 이동해야하는 상황에 사용하는 hook
(ex 로그인안된채로 마이페이지 접속했을 때 로그인페이지로 리다이렉트)

navigate 함수에
음수를 넣어주면 뒤로가기 양수는 앞으로가기

경로를 넣을수도 있다. navigate("/login");

replace도 가능하다. navigate('/board', { replace: true });

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

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

  const goBack = () => {
    navigate(-1); 
  };

  const goLogin = () => {
    navigate("/login");
  };

  return (
    <header>
      <button onClick={goBack}>뒤로가기</button>
      <button onClick={goLogin}>로그인</button>
    </header>
  );
};

export default Header;

 

NavLink

NavLink에서 사용한 경로와 현재 location 경로와 동일할 때 활성화 처리를 위해 사용한다.

스타일, 클래스를 적용해줄 수 있다.

<NavLink 
  style={({isActive}) => isActive ? activeStyle : undefined} 
/>

<NavLink 
  className={({isActive}) => isActive ? 'active' : undefined} 
/>

 

NotFound

해당되는 Route가 없는경우 404 페이지를 보여줄 경우 사용한다.

<Routes>
  <Route path="/" element={<Layout />}>
    <Route index element={<Main />}></Route>
    <Route path="/page1" element={<Page1 />}></Route>
    <Route path="/board/:id" element={<BoardDetail />}></Route>
  </Route>
  <Route path="/login" element={<Login />}></Route>
  <Route path="*" element={<NotFound />}></Route>
</Routes>

 

createBrowserRouter로 router를 선언했을 때는 errorElement을 이용할 수있다. 

router에서 맞는 경로를 못찾은경우 errorElement로 선언한 NotFound 컴포넌트가 그려진다. 

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    children: [
      {
        path: "about",
        element: <About />,
      },
      {
        path: "",
        element: <Home />,
      },
    ],
    errorElement: <NotFound />, //위에서 맞는경로를 못찾은 경우 
  },
]);

 

Navigate

컴포넌트를 화면에 보여주는 순간 다른페이지로 이동하고 싶을 때 사용하는 컴포넌트

  • 로그인 안한 상태로 마이페이지 접근했을때 로그인페이지로 redirect 되어야하는 경우
  • 페이지가 없는경우 메인페이지로 redirect 되어야하는 경우
// mypage
import { Navigate } from "react-router-dom";

const Mypage = () => {
  const isLogin = false;

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

  return <h1>마이페이지</h1>
};

export default Mypage;



참고

https://velog.io/@velopert/react-router-v6-tutorial#61-usenavigate