사실 이것도 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 |