TIL

[React] react-router-dom v6 에 대해

리용쓰 2022. 1. 14. 01:03

사실 이것도 HA 중간에 막히면서 알게 된 사실이다. react-router-dom v6로 업그레이드 되면서 여러가지가 달라진다.

HA 과제는 react-router-dom v5를 사용중이었고 Redirect 가 잘 되지 않아서 이것저것 구글링 중 알게 된 사실이다.

 

먼저

React Router v6은 React Hook을 많이 사용하므로 React Router v6으로 업그레이드를 시도하기 전에 React 16.8 이상에 있어야 합니다. 좋은 소식은 React Router v5가 React >= 15와 호환된다는 것입니다. 따라서 v5(또는 v4)를 사용 중이라면 라우터 코드를 건드리지 않고도 React를 업그레이드할 수 있어야 합니다. React 16.8로 업그레이드했으면 앱을 배포해야 합니다. 그런 다음 나중에 다시 돌아와서 중단한 부분부터 다시 시작할 수 있습니다.

라고 공식문서 안내 되어있다.

 

설치

$ npm install react-router-dom@6

//혹은

$ yarn add react-router-dom@6

package.json 에서 버젼을 확인 후 설치한다.

 

 1. Switch 대신에 Routes 를 사용

  • Switch 의 이름이 Routes로 바뀌었다.
  • exact 옵션이 사라지고 대신 *로 대체되었다.
  • component 방식이 달라졌다.
  • path를 기존 pah="/login/:id 에서 path=":id" 로 상대경로 지정
  • path="." 또는 path=".." 로 상대경로 지정 가능

기존의 Switch 방식 

import { BrowserRouter, Route, Switch } from "react-router-dom";
import Home from "./pages/Home";
import Write from "./pages/Write";

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/" component={() => <Home />} />
        <Route exact path="/write" component={() => <Write />} />
        <Route component={() => <div>Page Not Found</div>} />
      </Switch>
    </BrowserRouter>
  );
}

export default App;

Switch를 사용하고 exact 를 사용한다.

 

v6의 방식

import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { Main, Page1, Page2, NotFound } from "../pages";
import { Header } from ".";

const Router = () => {
  return (
    <BrowserRouter>
      <Header />
      <Routes>
        <Route path="/" element={<Main />} />
        <Route path="/page1/*" element={<Page1 />} />
        <Route path="/page2/*" element={<Page2 />} />
        <Route path="/*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;

Switch는 Routes로 이름이 바뀌었고, exact 는 사라지고 /*로 대체 한다. component 방식도 달라졌다.

 

 2. 중첩라우팅 사용하기

 

1)App.js 에서 중첩라우터를 사용하고 중첩라우터에서 Outlet 컴포넌트를 사용한다.



//App.js
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Web from "../Pages/Web";
import WebPost from "../Pages/WebPost";

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="web/*" element={<Web />}>
          <Route path=":id" element={<WebPost />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
};

export default Router;
// Web.js

import React from "react";
import { Link, Routes, Route, Outlet } from "react-router-dom";
import WebPost from "./WebPost";

const Web = () => {
  return (
    <div>
      <h1>This is Web</h1>
      <ul>
        <li>
          <Link to="1">Post #1</Link>
        </li>
        <li>
          <Link to="2">Post #2</Link>
        </li>
        <li>
          <Link to="3">Post #3</Link>
        </li>
        <li>
          <Link to="4">Post #4</Link>
        </li>
      </ul>

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

export default Web;

export default Web;

// --------------------------------------------------------------------------------
// WebPost.js

import React from "react";

const WebPost = () => {
  return <div>This is 포스트</div>;
};

export default WebPost;
  • App.js에서 자식 태그로 중첩하는 라우터를 기재하고, Web.js에서 Outlet 라이브러리를 통해 가져온다.
  • exact 안 쓰는 대신 /*가 필수이다

 

 

2) 곧바로 적용하는 방법

 

//App.js

import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Web from "../Pages/Web";

const Router = () => {
  return (
    <BrowserRouter>
      <Header />
      <Routes>
        <Route path="web/*" element={<Web />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;
// Web.js

import React from "react";
import { Link, Routes, Route} from "react-router-dom";
import WebPost from "./WebPost";

const Web = () => {
  return (
    <div>
      <h1>This is Web</h1>
      <ul>
        <li>
          <Link to="1">Post #1</Link>
        </li>
        <li>
          <Link to="2">Post #2</Link>
        </li>
        <li>
          <Link to="3">Post #3</Link>
        </li>
        <li>
          <Link to="4">Post #4</Link>
        </li>
      </ul>
      <Routes>
        <Route path=":id" element={<WebPost />} />
      </Routes>
    </div>
  );
};

export default Web;

// --------------------------------------------------------------------------------
// WebPost.js

import React from "react";

const WebPost = () => {
  return <div>This is 포스트</div>;
};

export default WebPost;

 

3.  props

useLocation 과 useParams 의 사용

 

useLocation 사용예시

 

pathname 을 가져와 Styled-Component 와 결합하기

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

const HeaderWrapper = styled("header")`
  margin-bottom: 30px;
`;
const List = styled("ul")`
  display: flex;
`;
const Item = styled("li")`
  margin-right: 20px;
  text-transform: uppercase;
  font-weight: 600;
  color: ${(props) => (props.selected ? "white" : "black")};
  background-color: ${(props) => (props.selected ? "#f1c40f" : "white")};
`;

const Header = () => {
  const { pathname } = useLocation();
  return (
    <HeaderWrapper>
      {/* header 태그 */}
      <List>
        {/* ul 태그 */}
        <Item selected={pathname.startsWith("/web")}>
          {/* li 태그 */}
          <Link to="/web">Go to Web</Link>
        </Item>
        <Item selected={pathname === "/design"}>
          <Link to="/design">Go to Design</Link>
        </Item>
        <Item selected={pathname === "/server"}>
          <Link to="/server">Go to Server</Link>
        </Item>
      </List>
    </HeaderWrapper>
  );
};

export default Header;

useLocation Hook을 사용하여 pathname 을 가져올 수 있다.

 

 

 

useParams 의 예시

 

:id path 이용하기

// WebPost.js

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

const WebPost = () => {
  const { id } = useParams();
  return <div>#{id}번째 포스트</div>;
};

export default WebPost;

useParams Hook을 사용하여 :id 값을 가져왔다.

 

 

4. useHistory 에서 useNavigate로

 

useHistory 는 Link 와 비슷한 기능을 하는 Hook이다. 뒤로가기를 만들거나 회원가입을 완료 한 후 메인 화면으로 자동으로 넘어가게 하게하는 기능을 만들 수 있다. 그 기능을 이젠 useNavigete 로 사용한다.

useHistory 의 예시 코드

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

function App() {
  let history = useHistory();
  function handleClick() {
	    history.push("/home");
  }
  return (
    <div>
      <button onClick={handleClick}>go home</button>
    </div>
  );
} 

// v5
import { useHistory } from "react-router-dom";

function App() {
  const { go, goBack, goForward } = useHistory();

  return (
    <>
      <button onClick={() => go(-2)}>
        Go 2 pages back
      </button>
      <button onClick={goBack}>Go back</button>
      <button onClick={goForward}>Go forward</button>
      <button onClick={() => go(2)}>
        Go 2 pages forward
      </button>
    </>
  );
}

 useHistory 에서 goBack, goForward,go 기능은 뒤로가기, 앞으로가기, 해당위치로 의 기능을 담당했다. 이젠

useNavigate를 사용하여 navigate로 통일하고 index를 넣음으로 해결 할 수 있다.

 

useNavigate 예시코드

 

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

function App() {
  let navigate = useNavigate();
  function handleClick() {
    navigate("/home");
  }
  return (
    <div>
      <button onClick={handleClick}>go home</button>
    </div>
  );
}

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

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

  return (
    <>
      <button onClick={() => navigate(-2)}>
        Go 2 pages back
      </button>
      <button onClick={() => navigate(-1)}>Go back</button>
      <button onClick={() => navigate(1)}>
        Go forward
      </button>
      <button onClick={() => navigate(2)}>
        Go 2 pages forward
      </button>
    </>
  );
}

만약 useHistory의 replace 기능이 필요하다면, navigate(to='가고자하는 path', {replace: true})의 형태로 사용 할 수 있다.

state 가 필요하다면 navigate(to='path', { state }) 형태로 사용 하면 된다.

 

5. useRoutes

기존엔 react-router-config 를 설치해서 사용하였지만 이젠 useRoutes Hook을 사용하면 된다.

** 여기서 react-router-config 란??

https://velog.io/@naseriansuzie/TIL32 참조

  • "리액트 라우터를 사용할 때 정적으로 라우트 환경 설정을 할 수 있는 헬퍼 기능" 이라고 나 나름대로 번역해 보았다. 위에서 말한 것처럼 컴포넌트 형식으로 라우팅을 정의하는 방식 말고, file config 형식으로 라우팅에 필요한 컴포넌트와 주소 그리고 기타 참조값들을 정리해둘 수 있는 기능이다.

**

 

 react-router-config 를 사용했을 때 예시

 

// react-router-config
// yarn add react-router-config로 설치 후 사용
import { renderRoutes } from "react-router-config";

const routes = [
  {
    component: Root,
    routes: [
      {
        path: "/",
        exact: true,
        component: Home
      },
      {
        path: "/child/:id",
        component: Child,
        routes: [
          {
            path: "/child/:id/grand-child",
            component: GrandChild
          }
        ]
      }
    ]
  }
];

const Root = ({ route }) => (
  <div>
    <h1>Root</h1>
    {/* 자식 라우트들이 렌더할 수 있도록  renderRoutes 실행 */}
    {renderRoutes(route.routes)}
  </div>
);

const Home = ({ route }) => (
  <div>
    <h2>Home</h2>
  </div>
);

const Child = ({ route }) => (
  <div>
    <h2>Child</h2>
    {/*  renderRoutes가 없으면 자식들은 렌더되지 않음  */}
    {renderRoutes(route.routes)}
  </div>
);

const GrandChild = ({ someProp }) => (
  <div>
    <h3>Grand Child</h3>
    <div>{someProp}</div>
  </div>
);

ReactDOM.render(
  <BrowserRouter>
    {/* renderRoutes에 가장 처음 정의했던 routes 자체를 뿌려줌으로써 차례로 렌더링될 수 있도록 함 */}
    {renderRoutes(routes)}
  </BrowserRouter>,
  document.getElementById("root")
);

 

useRoutes 를 사용했을 때의 예시

 

function App() {
  let element = useRoutes([
		// Route에서 사용하는 props의 요소들과 동일
    { path: "/", element: <Home /> },
    { path: "dashboard", element: <Dashboard /> },
    {
      path: "invoices",
      element: <Invoices />,
			// 중첩 라우트의 경우도 Route에서와 같이 children이라는 property를 사용
      children: [
        { path: ":id", element: <Invoice /> },
        { path: "sent", element: <SentInvoices /> }
      ]
    },
		// NotFound 페이지는 다음과 같이 구현할 수 있음
    { path: "*", element: <NotFound /> }
  ]);
	
	// element를 return함으로써 적절한 계층으로 구성된 element가 렌더링 될 수 있도록 함
  return element;
}

 

 

출처

https://velog.io/@soryeongk/ReactRouterDomV6 

 

[React] react-router-dom v6 업그레이드 되면서 달라진 것들

react-router-dom이 v6으로 업그레이드 되었습니다 :) v5와 다른 점이 몇 가지 있으니 꼭 숙지하시기 바랍니다. 안그럼 아무것도 실행되지 않을지도....

velog.io

https://abangpa1ace.tistory.com/209?category=905014 

 

[React Router/lib.] React Router v6

오랜만에 React 학습을 진행하는데, React Router가 6버전이 출시되었다고 한다. 기존에 사용하던 문법들이 일부 수정된 것을 감안하여, 이를 한번 훑고자 짧게나마 포스팅을 적는다. 💙 개요 React Rou

abangpa1ace.tistory.com

 

'TIL' 카테고리의 다른 글

[node.js] Bcrypt 를 이용한 비밀번호 암호화  (0) 2022.03.18
[node.js] multer 미들웨어를 이용해 서버에서 파일 다루기  (0) 2022.02.24
Sequelize 다루기  (0) 2021.12.25
Git branch  (0) 2021.12.01
MVC 패턴  (0) 2021.11.22