woolta

react-router v6에서는 어떤것들이 변했을까??

wooltaUserImgb00032 | React | 2021-03-27

react-router v6에서 바뀐점 알아보기

react-routerreact 에서 브라우저 라우팅을 관리하기 위해 사용하는 라이브러리로 react 를 통한 작업시 밥과 김치 처럼 거의 같이 쓰는 라이브러리 입니다.

이번에는 react-router 가 v6 로 업데이트 하면서 변경되는 점에 대해 알아보려 합니다. 물론 아직 정식 오픈은 되지 않고 베타 단계인 상태 입니다. 현재 글 작성 기준 preRelease 상태입니다. :)

v5에서 v6로 migration

v5 에서 v6로 미리 migration을 진행해보고 싶으신 경우 migrating-5-to-6 를 참고 하여 진행하실 수 있습니다. 이때 react 요구 버전이 16.8 이상 이기 때문에 migration을 준비중이라면 react의 버전도 꼭 확인해주셔야 합니다. :)

놀랍도록 작아진 번들 사이즈

react-router v6 는 아래 이미지와 같이 이전 버전 대비 약 70% 정도의 크기가 줄어든 것을 확인 하실 수 있습니다. 이는 버전만 업데이트 하더라도 번들 크기에 대한 최적화가 가능하다는 이점이 존재합니다. :)

https://image.woolta.com/3fef4c9fdcdad68d.png

switch -> routes 네이밍 변경

기존의 route들을 구성하는 부모 요소를 switch 라는 네이밍으로 사용하였는데 route의 복수개를 뜻하는 routes 로 이름이 변경되었습니다. 바뀐 네이밍이 개인적으로는 더욱 직관적이라 마음에 드는 부분입니다.

// v5
<Switch>
  <Route ... />
</Routes>

// v6
<Routes>
  <Route ... />
</Routes>

StaticRouter 의 import 위치 변경

다음과 같이 StaticRouter 의 import 패키지 경로가 변경되었습니다. :)

// v5
import { StaticRouter } from 'react-router-dom';
// v6
import { StaticRouter } from 'react-router-dom/server';

exact 옵션 삭제

기존의 / 라우트의 경우 React Router의 디폴트 매칭 규칙 으로 인해 앞부분만 일치해도 전부 매칭되기때문에 정확히 라우트를 일치시키고자 exact 속성을 사용하였으나 v6부터 기본적으로 정확히 일치하도록 매칭 규칙이 변하여 v6에서부터는 exact 의 옵션을 더이상 사용하지 않습니다. 만약 하위경로에 여러 라우팅을 매칭시키고 싶다면 다음과 같이 URL 뒤에 * 을 사용하여 일치시킬 수 있습니다.

// categores 로 시작되는 모든 라우팅 매칭
<Route path='categories/*' />

route 에서 컴포넌트 렌더링

이전 버전에서는 컴포넌트를 렌더링 하기 위해선 Route 컴포넌트의 render 속성에 arrowFunction 을 사용하여 컴포넌트를 렌더링 하는 방식으로 사용하였습니다. 물론 기본적으로는 component 속성에 넣어주기도 하지만 컴포넌트를 렌더링 해야 하는 경우는 render 속성을 사용해야 하는데 이때 arrowFunction 으로 선언되는 부분을 v6에서는 element 속성을 통해 바로 넣어줄 수 있도록 개선되었습니다. 아래 예제를 보면 v5 대비 훨씬 직관적인 코드로 작성할 수 있도록 개선된 것을 확인하실 수 있습니다. :)

import UserInfo from './UserInfo'; // 

// v5 버전 사용 예시
<Route path='user' component={UserInfo} />
<Route
  path='user'
  render={routeProps => (
    <UserInfo routeProps={routeProps} isLogin={true} />
  )}
/>

// v6 버전 사용 예시
<Route path='user' element={<UserInfo />} />
<Route path='user' element={<UserInfo isLogin={true} />} />

간편해진 중첩 라우팅

기존버전(v5)에서는 중첩 라우팅을 사용하기 위해선 중첩되는 컴포넌트에서 useRouteMatch 훅을 사용해 path를 얻어 이를 추가 조합하는 방식으로 구성하였습니다.

v5 중첩 라우팅 사용 예시

import {
  BrowserRouter,
  Switch,
  Route,
  Link,
  useRouteMatch
} from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/user" component={User} />
      </Switch>
    </BrowserRouter>
  );
}

function User() {

  const { path } = useRouteMatch();
  return (
    <div>
      <Switch>
        <Route path={`${path}/detail`}>
          <UserDetail />
        </Route>
      </Switch>
    </div>
  );
}

v6버전에서는 하나의 파일에 모든 경로를 지정하고 중첩영역 렌더링 요소에는 Outlet 속성을 제공하여 더욱 간결하게 중첩된 라우트 구조를 사용하도록 개선되었습니다.

특히 중첩된 라우팅요소도 최상단에서 관리가 가능해 라우팅에 요소를 한곳으로 모을수 있어 개인적으로는 상당히 마음에 드는 부분입니다. :)

v6 중첩 라우팅 사용 예시

import {
  BrowserRouter,
  Routes,
  Route,
  Outlet
} from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path='user' element={<User />} >
          <Route path='detail' element={<UserDetail />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

function User() {
  return (
    <>
      <Outlet />
    </>
  )
}

useHistory 훅 변경 -> useNavigate

v6에서는 useHistory 훅에 대한 네이밍을 useNavigate 로 변경되었으며 기존의 push, replace 등의 메소드로 동작하는 부분을 다음과 같이 변경하였습니다. 이부분에 대해선 지극히 개인적으로 기존의 push, replace 의 메소드를 호출하는게 좀더 직관적으로 보이지 않을까?? 하는 생각이 있습니다. :)

// v5
const history = useHistory();

history.push('/home');
history.replace('/home');

// v6
const navigate = useNavigate();

navigate('/home');
navigate('/home', {replace: true});

// v6 에서의 앞으로, 뒤로 가기 사용방법 변화 
<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>

react-router-config 대신 useRoutes 를 사용하세요.

기존의 react-router-config 가 v6 에서 useRoutes 라는 훅으로 이동되었습니다. 이제 별도로 패키지를 추가설치 하지 않고 useRoutes 훅을 사용해 routes 를 구성할 수 있게 되었습니다. :)

function App() {
  const element = useRoutes([
    // These are the same as the props you provide to <Route>
    { path: '/', element: <Home /> },
    { path: 'dashboard', element: <Dashboard /> },
    { path: 'invoices',
      element: <Invoices />,
      // Nested routes use a children property, which is also
      // the same as <Route>
      children: [
        { path: ':id', element: <Invoice /> },
        { path: 'sent', element: <SentInvoices /> }
      ]
    },
    // Not found routes work as you'd expect
    { path: '*', element: <NotFound /> }
  ]);

  // The returned element will render the entire element
  // hierarchy with all the appropriate context it needs
  return element;
}

참고

Copyright © 2018 woolta.com

gommpo111@gmail.com