npm i react-router-dom
react-router-dom
v6 이전 버전을 쓰고 싶다면 npm i react-router-bom@version
npm i react-router-bom@5.3.0
react-router-dom
v6 참고글// Router.tsx
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Post from "./routes/Post";
import Posts from "./routes/Posts";
function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Posts />} />
<Route path=":postId" element={<Post />} />
</Routes>
</BrowserRouter>
);
}
export default Router;
BrowserRouter
는 URL history를 스택으로 저장하여 탐색을 도와주는 인터페이스이다.Routes
는 v5의 Switch
역할이며, Route
의 요소를 살펴 가장 일치하는 항목을 찾아 UI에 렌더링한다.Route
는 element
에 할당된 컴포넌트와 path
를 렌더링한다.path
의 :postId
는 개별 경로의 파라미터로 작동한다./post
이고 post id가 1
인 경우 URL은 /post/1
이 된다.useParams
를 사용해 하위 컴포넌트의 파라미터를 가져올 수 있다.import { useParams } from "react-router-dom";
function Post() {
const params = useParams();
console.log(params);
// {postId: '1'}
return (...rendering);
}
export default Post;
Post
컴포턴트에 접근했다면 params
는 {postId: '1'}
를 가져온다.<a>
는 클릭 시 페이지를 새로고침하기 때문에 <Link>
를 사용한다.const posts = [
{
id: "1",
name: "js",
content: "Javascript",
rank: 1,
},
{
id: "2",
name: "ts",
content: "Typescript",
rank: 2,
},
{
id: "3",
name: "ps",
content: "Pyscript",
rank: 3,
},
];
function Posts() {
return (
<div>
{posts.map((post) => (
<Post key={post.id}>
<Link to={`/${post.id}`}>{post.name}</Link>
</Post>
))}
</div>
);
}
export default Posts;
to
는 Route
의 path
에 매칭되는 컴포넌트로 가는 경로이다.<Post />
컴포넌트 페이지로 이동한다.function Posts() {
return (
<div>
{posts.map((post) => (
<Post key={post.id}>
<Link
to={`/${post.id}`}
state={{
name: post.name,
content: post.content,
rank: post.rank,
}}
>
{post.name}
</Link>
</Post>
))}
</div>
);
}
export default Posts;
state
속성에 넘겨줄 데이터를 담는다.Post
컴포넌트에서 useLocation()
을 통해 받은 데이터를 확인할 수 있다.import { useLocation } from "react-router-dom";
function Post() {
const loc = useLocation()
console.log(loc)
return (...rendering);
}
export default Post;
// 출력
hash: ""
key: "blabla"
pathname: "/1"
search: ""
state: {name: 'js', content: 'Javascript',rank: 1}
[[Prototype]]: Object
state
에 모두 담겨 있다.ts
는 담긴 데이터들의 타입을 모르므로 정의한다.Generic
을 지원하지 않는다고 한다. 따라서 as
를 사용했다.interface StateTypes {
state: {
name: string;
content: string;
rank: number;
};
}
function Post() {
const { state } = useLocation() as StateTypes;
// v5
// const { state } = useLocation<StateTypes>();
return (
<div>
<span>{state.name}</span>
<span>{state.content}</span>
<span>{state.rank}</span>
</div>
);
}
export default Post;
Nested Route
라고 한다.Post
컴포넌트 내에서 Replies
와 Members
를 이동하는 Route
를 설정할 수 있다.Nested Route
를 구성할 수 있다.Router
와 분리하여 부모 컴포넌트에 Route
를 추가하는 방법이다.// Router.tsx
(...imports)
function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Posts />} />
<Route path=":postId*" element={<Post />} />
</Routes>
</BrowserRouter>
);
}
export default Router;
// Post.tsx
import { Route, Routes } from "react-router-dom";
import Replies from "./Replies";
import Members from "./Members";
function Post() {
return (
<div>
<Routes>
<Route path="replies" element={<Replies />} />
<Route path="members" element={<Members />} />
</Routes>
</div>
);
}
export default Post;
path
를 가지려면 부모 컴포넌트 path
에 *
를 추가해야 한다.Router.tsx
처럼 Route
를 구성한다.Router.tsx
로 몰아 넣고, 자식 path
가 들어갈 자리에 Outlet
을 위치시킨다.// Router.tsx
(...imports)
function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Posts />} />
<Route path=":postId*" element={<Post />} />
<Route path="replies" element={<Replies />} />
<Route path="members" element={<Members />} />
</Routes>
</BrowserRouter>
);
}
export default Router;
// Post.tsx
import { Outlet } from "react-router-dom";
import Replies from "./Replies";
import Members from "./Members";
function Post() {
return (
<div>
<Outlet />
</div>
);
}
export default Post;
Outlet
이 위치한 컴포넌트 path
에 자식 path
를 적으면 url은 추가되나 페이지 변경은 일어나지 않는다.import { createBrowserRouter } from "react-router-dom";
import Root from "./Root";
import About from "./screens/About";
import Home from "./screens/Home";
import Other from "./screens/Other";
import NotFound from "./screens/NotFound";
import ErrorComponent from "./components/ErrorComponent";
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "",
element: <Home />,
errorElement: <ErrorComponent />,
},
{
path: "about",
element: <About />,
},
],
errorElement: <NotFound />,
},
{
path: "/other",
element: <Other />,
},
]);
export default router;
Router.tsx
의 BrowserRouter
를 createBrowserRouter
로 수정한다.createBrowserRouter
의 인자는 라우팅할 경로와 컴포넌트 객체로 이뤄진 배열이다.children
프로퍼티는 하위 경로이다.<Root />
내 <Navigation />
을 <Home />
과 <About />
은 볼 수 있지만, <Ohter />
는 다른 상위 경로이므로 볼 수 없다.errorElement
는 페이지에 문제가 생겼을 때 보여줄 화면을 렌더링한다.errorElement
에 <NotFound />
를 렌더링했을 경우, 잘못된 경로 접근 시 동작한다.errorElement
에 <ErrorComponent />
를 렌더링했을 경우, 해당 경로에서 문제가 발생했을 시 동작한다.errorElement
가 없다면 컴포넌트가 충돌했을 때 앱을 죽여버리기 때문에 보호를 위해서 작성하는 것이 좋다.import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "react-router-dom";
import router from "./Router";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
index
컴포넌트에 <RouterProvider router={router} />
를 추가한다.import { Outlet } from "react-router-dom";
import Navigation from "./components/Navigation";
function Root() {
return (
<div>
<Navigation />
<Outlet />
</div>
);
}
export default Root;
<Outlet />
을 통해 하위 컴포넌트가 렌더링할 위치를 정한다.import { Link, useNavigate } from "react-router-dom";
function Navigation() {
const navigate = useNavigate();
const onAboutClick = () => {
navigate("/about");
};
return (
<header>
<ul>
<li>
<Link to={"/"}>Home</Link>
</li>
<li onClick={onAboutClick}>About</li>
</ul>
</header>
);
}
export default Navigation;
<Link>
를 대신할 수 있다.to
를 인자로 받으며, 해당 경로 외에 -1
은 뒤로가기
를 의미한다.import { createBrowserRouter } from "react-router-dom";
import Root from "./Root";
import Home from "./screens/Home";
import User from "./screens/User";
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "",
element: <Home />,
},
{
path: "users/:userId",
element: <User />,
},
],
},
]);
export default router;
:{bla}
로 설정한 경로는 URL의 파라미터가 된다.import { useParams } from "react-router-dom";
function User() {
const { userId } = useParams();
return <h1>User {userId}</h1>;
}
export default User;
useParams
를 통해 파라미터를 받아와 활용할 수 있다.path
가 담겨 있는지 확인할 수 있는 기능이다.path
가 있다면 url 정보는 반환하고, 아니라면 null
을 반환한다.import { useMatch } from "react-router-dom";
function Post() {
const match = useMatch("/post");
return (
<div>
<h1>Here is Post Component</h1>
</div>
);
}
export default Post;
Outlet
은 위에서 언급했듯, 하위 경로를 렌더링한다.// Router.tsx
const router = createBrowserRouter([
{
// (...)
{
path: "users/:userId",
element: <User />,
children: [
{
path: "followers",
element: <Followers />,
},
],
},
],
},
]);
// User.tsx
function User() {
// (...)
return (
<div>
<h1>User {params.userId}</h1>
<hr />
<Link to="followers">See Followers</Link>
<Outlet />
</div>
);
}
Link
에 /{path}
를 사용하면 절대경로로 이동한다. 예를 들어, /followers
를 사용하면 http://localhost:3000/followers
를 가리킨다./
없이 {path}
를 사용하면 해당 경로의 하위 경로로 추가된다.import { Link, Outlet, useParams } from "react-router-dom";
import { users } from "../../db";
function User() {
const { userId } = useParams();
return (
<div>
<h1>
User {userId} Name : {users[Number(userId) - 1].name}
</h1>
<hr />
<Link to="followers">See Followers</Link>
<Outlet
context={{
nameOfMyUser: users[Number(userId) - 1].name,
}}
/>
</div>
);
}
export default User;
Outlet
의 context
어트리뷰트에 상태를 입력하면 하위 경로에서 해당 상태를 불러와 사용할 수 있다.import { useOutletContext } from "react-router-dom";
interface FollowersContextProps {
nameOfMyUser: string;
}
function Followers() {
const { nameOfMyUser } = useOutletContext<FollowersContextProps>();
return <h1>{nameOfMyUser}'s Followers</h1>;
}
export default Followers;
useOutletContext
는 상위 경로에서 보낸 상태를 포함한다.query
를 가져올 때 사용한다.import { useSearchParams } from "react-router-dom";
function Home() {
const [readSearchParams, setSearchParams] = useSearchParams();
console.log(readSearchParams.has("query")); // false
setSearchParams({ query: "search" }); // http://localhost:3000/?query=search
console.log(readSearchParams.get("query")); // search
return (
<div>
// (...)
</div>
);
}
export default Home;
useSearchParams
는 useState
와 비슷하게 사용한다.readSearchParams
는 URL에 담긴 query에 대한 접근을 도와준다.JavaScript
의 URLSearchParams
인스턴스를 호출하고, 해당 인스턴스의 메서드를 사용한다.setSearchParams
는 URL query를 설정한다.참고
노마드 코더 - React JS 마스터클래스
React Router v6 Docs
@soryeongk님 velog - React Router v6 변경점