React 는 보통 SPA(Single Page Application) 을 개발하는데 사용하는 Web Frontend UI Library 입니다. SPA 는 CSR 로서 전통적인 SSR 방식과는 다르게 작동합니다. CSR 는 브라우저에서 제공하는 많은 기능을 이용하며, 서버에서 페이지가 내려오는 SSR 와는 다르게, 처음 제공하는 페이지에서 벗어나지 않고 변경되는 데이터를 서버에서 받아와 Client (브라우저) 에서 UI 를 랜더링 하는 방식입니다. 즉, CSR 에서는 물리적인 페이지의 이동이 없기에 페이지 기능을 구현하기 위해서는 써드 파티 라이브러리를 사용합니다. React 에서는 대부분 React-router 이라는 써드 파티 라이브러리를 이용해 편리하게 라우팅을 구현할 수 있습니다.
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 이상이여야 합니다.
<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;
이제 <Route>
태그 내부에 <Route>
를 선언하는 식으로 중첩 라우팅을 사용할 수 있으며 중첩 라우터에서 <Outlet>
컴포넌트를 사용하여 쉽게 중첩 라우팅을 할 수 있습니다.
// list 에서 detail 을 라우팅 하는 경우
function Router() {
return (
<Routes>
<Route path="/list" element={<List/>} >
<Route path="/detail/:id" element={<Detail/>}/>
</Route>
</Routes>
);
}
또 v6 부터는 라우터의 path 가 상대 경로로 바뀌었습니다.
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
의 변화기존의 <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
공식 홈페이지 : 바로가기