React Router v6

Thomas·2022년 6월 26일
0

React Router 을 왜 사용할까?

React 는 보통 SPA(Single Page Application) 을 개발하는데 사용하는 Web Frontend UI Library 입니다. SPA 는 CSR 로서 전통적인 SSR 방식과는 다르게 작동합니다. CSR 는 브라우저에서 제공하는 많은 기능을 이용하며, 서버에서 페이지가 내려오는 SSR 와는 다르게, 처음 제공하는 페이지에서 벗어나지 않고 변경되는 데이터를 서버에서 받아와 Client (브라우저) 에서 UI 를 랜더링 하는 방식입니다. 즉, CSR 에서는 물리적인 페이지의 이동이 없기에 페이지 기능을 구현하기 위해서는 써드 파티 라이브러리를 사용합니다. React 에서는 대부분 React-router 이라는 써드 파티 라이브러리를 이용해 편리하게 라우팅을 구현할 수 있습니다.

React Router v6.3.0

React router DOM 의 v6 은 2022 년 4월 1일에 릴리즈 되었습니다.

지난 4월 React 의 버전이 18 로 업그레이드 되었을 때 저희 회사의 제품인 Playce RORO 의 React 의 버전을 업그레이드 하는데 있어서 React-Router-DOM 의 버전 업그레이드에서 애를 먹었는데 새로운 솔루션의 아키텍처에서는 최신 버전의 React-Router-DOM 을 사용하기 위해서 무엇이 달라졌는지 알아보고, 이를 팀원들에게 공유해보고자 글을 작성해봅니다.

고려해야 할 점

먼저 React-Router v6 로 업데이트 되면서 많은 내용이 React Hook 으로 활용되기 때문에 React 의 버전이 16.8 이상이여야 합니다.

#.1 <Switch>

첫 번째 변경점은 태그를 더 이상 지원하지 않는다는 점입니다. 기존의 코드를 살펴봅시다.

//react-router-dom v5

import React, { ReactElement } from 'react';
import { Redirect, Route, Switch, useLocation } from 'react-router-dom';

import * as routePath from 'common/const/route-path';

import Dashboard from './dashboard';
import CloudReadiness from './cloudreadiness';

function OverviewRoute(): ReactElement {
  const { state } = useLocation();
  return (
    <Switch>
      <Route path={routePath.PATH_MAIN_DASHBOARD} render={(props) => <Dashboard />} />
      <Route path={routePath.PATH_MAIN_CLOUD_READINESS} render={(props) => <CloudReadiness />} />
      <Redirect
        path={routePath.PATH_MAIN}
        to={{
          pathname: routePath.PATH_MAIN_DASHBOARD,
          state,
        }}
      />
    </Switch>
  );
}

export default OverviewRoute;

기존의 코드에서는 Router의 분기를 Switch 태그 내부에서 태우고 있으며, Route 태그 내부에서는 render 속성을 활용해 이동할 페이지를 주입하고 있습니다.

v6 이후 에서는 <Switch> 대신 <Routes> 를 사용하게 됩니다.

또한 <Route> 태그 내부에서 element 속성 안에 JSX 태그를 직접 전달해줌으로써 보다 간결하게 표현이 가능합니다.

<Route> 태그 내부에서 사용할 수 있었던 exact 속성이 더 이상 지원하지 않고, 여러 라우팅을 매칭하고 싶은 경우엔 URL 뒤 * 을 사용해야 합니다.

import React, { ReactElement } from 'react';
import {  Route, Routes, useLocation } from 'react-router-dom';

import * as routePath from 'common/const/route-path';

import Dashboard from './dashboard';
import CloudReadiness from './cloudreadiness';

function OverviewRoute(): ReactElement {
  const { state } = useLocation();
  return (
    <Routes>
      <Route path={routePath.PATH_MAIN_DASHBOARD} element={<Dashboard/>} />
      <Route path={routePath.PATH_MAIN_CLOUD_READINESS} element={<CloudReadiness/>} />
    </Routes>
  );
}

export default OverviewRoute;

#2. 중첩 라우팅

이제 <Route> 태그 내부에 <Route> 를 선언하는 식으로 중첩 라우팅을 사용할 수 있으며 중첩 라우터에서 <Outlet> 컴포넌트를 사용하여 쉽게 중첩 라우팅을 할 수 있습니다.

// list 에서 detail 을 라우팅 하는 경우

function Router() {
  return (
    <Routes>
      <Route path="/list" element={<List/>} >
        <Route path="/detail/:id" element={<Detail/>}/>
      </Route>
    </Routes>
  );
}

또 v6 부터는 라우터의 path 가 상대 경로로 바뀌었습니다.

#3. useHistory 의 삭제, useNavigate 의 등장

React-Router-DOM v6 부터는 useHistory 가 삭제 되었으며, useNavigate 를 활용해 history 객체를 사용했던 것 처럼 활용을 할 수 있습니다.

function Example() {
  const navigate = useNavigate();
  cosnt letsGo = () => {
    navigate('/', {
      state: {
        id: 1,
        name: "lego"
      }
    });
  }
  return (
    <div>
      <button onClick={letsGo}>letsgo</button>
    </div>
  );
}

function LetsGo() {
  const {state} = useLocation();
  return (
    <div>
      {state?.id}
    </div>
  );
}

위 코드를 살펴보면 navigate 객체를 활용해 페이지를 전환하였으며, 기존의 history 객체를 활용해 push 할 때 state 를 전달해줬던 방법과 비슷하게 state 를 전달해주고 있습니다.

이는 라우팅 된 페이지에서 useLocation 훅을 활용해, location.state 으로 받아서 사용할 수 있습니다.

기존의 history 의 replace 를 활용하고 싶다면 navigate 인자로 설정해서 활용할 수 있습니다. useHistory 훅을 통해서 활용을 할 수 있는 go, goForward, goBack 기능은 navigate 의 인자로 숫자를 넣어줌으로서 보다 직관적으로 사용할 수 있게 되었습니다.

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

  const handleClick = () => {
    navigate("/list", { replace: true });
  };
  
  const handleBackTwoPages = () => {
    navigate(-2);
  };
  
  return (
    <div>
      <Button onClick={handleClick}>Click</Button>
      <Button onClick={handleBackTwoPages}>Go back 2 page</Button>
    </div>
  );
}

기존의 <NavLink> 에서는 activeClassName, activeStyle 을 활용해 활성화 될 때 스타일을 지정해 줄 수 있었습니다.

v6 에서는 윗 속성들이 사라지고 대신 className 에 함수를 전달해 줄 수 있으며, 함수 내부에 isActive 라는 변수를 받아서 스타일을 지정해줄 수 있게 되었습니다.

function IsActive() {
  const navLinkStyle = ({isActive}) => ({
    color: isActive ? "blue" : "black",
    fontSize: isActive ? "14px" : "12px",
  });
  return (
    <div>
      <NavLink to="/" className={navLinkStyle}>Click!</NavLink>
      <NavLink to="/list" className={({isActive}) => ({color: isActive ? "red" : "green"})}>Click!</NavLink>
    </div>
  );
}

간단한 연습

React-Router-DOM v6 변경점을 확인해보고자 간단한 예제를 만들어봤습니다.

어플리케이션의 흐름은 아래와 같습니다.

아래는 주요 코드를 발췌해봤습니다.

Routes.tsx 내부에서 변경된 Routes → Route 를 확인해볼 수 있으며, 중첩 라우팅을 확인할 수 있습니다.

또한 컴포넌트 (페이지) 내부에서는 useNavigate 를 활용해 페이지를 전환합니다.

// Routes.tsx
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Detail from "./pages/Detail";
import List from "./pages/List";
import Main from "./pages/Main";
import Result from "./pages/Result";
import Search from "./pages/Search";

function Router() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="list" element={<List />}>
          <Route path=":id/detail" element={<Detail />} />
        </Route>
        <Route path="search" element={<Search />} />
        <Route path="result" element={<Result />} />
        <Route path="/" element={<Main />} />
      </Routes>
    </BrowserRouter>
  );
}

export default Router;
// Main.tsx
import React from "react";
import { useNavigate } from "react-router-dom";

function Main() {
  const navigate = useNavigate();
  const goList = () => {
    navigate("/list", {
      state: "temp State",
    });
  };
  const goSearch = () => {
    navigate("/search");
  };
  return (
    <div>
      <h1>Main Page</h1>
      <button onClick={goList}>Go List</button>
      <br />
      <button onClick={goSearch}>Go Search</button>
    </div>
  );
}

export default Main;
//Detail.tsx
import React from "react";
import { useParams, useNavigate } from "react-router-dom";
import { mockData } from "./List";

function Detail() {
  const { id } = useParams();
  const navigate = useNavigate();

  const detailData = mockData.find((data) => data.id === +(id as string));

  const goMain = () => {
    navigate("/");
  };
  return (
    <>
      <h1>this is Detail of {detailData?.title}</h1>
      <div>
        <p>desc: {detailData?.desc}</p>
      </div>
      <div>
        <button onClick={goMain}>go Main Page</button>
      </div>
    </>
  );
}

export default Detail;

전체 코드 확인하기>

마무리하며..

React-Router-DOM v6 은 출시된지 반년이 넘어서 참고할 만한 포스팅이 많습니다. 또한 React 를 활용한 프로젝트를 할 경우 대부분 사용하며 레퍼런스도 많고 문서도 잘 정리되어 있어서 쉽고 편하게 사용할 수 있습니다.

저희 팀 Playce Dev 의 새로운 아키텍처에서는 최신 버전의 React-Router-DOM 을 활용해 더욱 편리하게 개발할 수 있는 날을 꿈꾸며 짧은 포스팅을 마무리 하겠습니다.

읽어봐주셔서 감사합니다.

https://velog.io/@soryeongk/ReactRouterDomV6
https://kyung-a.tistory.com/36
https://blog.woolta.com/categories/1/posts/211
공식 홈페이지 : 바로가기

profile
안녕하세요! 주니어 웹 개발자입니다 😆

0개의 댓글