$ yarn add react-router-dom@6
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
BrowserRouter
로 감싸야한다. 이렇게 해야만 해당 App 에서 브라우저 라우팅 기능을 사용할 수 있다.폴더 구조 관련 :
routes 폴더를 만들고 그 안에다가 컴포넌트 파일을 넣어주기도 하는데 정답이 정해져있는 것이 아니므로, 프로젝트 등을 진행하실 때에는 팀 내에서 폴더 구조를 협의하고 시작하는 것을 추천!
// App.js
import { Link, Route, Routes } from 'react-router-dom';
<Route path="posts" element={<Posts/>}/>
<Link to="posts">Posts</Link>
a
태그가 아니라 Link
태그 사용한다.<Route path="posts" element={<Posts/>}>
<Route path=":postId" element={<PostDetail/>}/>
</Route>
Posts 페이지에서는 글 제목만 보여주고, 제목을 누르면 PostDetail 페이지가 보이는 형태
이러한 형태를 Nested Route
라고 한다. 서브 라우트라고도 표현하는데, 이렇게 작성하게 되면 URL 구조가 주소/posts/:postId 와 같이 계층적으로 이어지면서 설정된다.
뿐만 아니라 Nested Route 를 쓰면 Outlet
이라는 것을 통해서, 부모 Route 의 요소를 표시하면서 동시에 하위 Route 요소를 표시하게 된다.
:postId
처럼 문자 앞에 :
를 써주게 되면, 그때부터는 단어 그 자체가 아니라 변수로서 인식하겠다는 뜻이 됩니다. 그래서 이렇게 작성하면 posts/1
이라는 주소로 사용자가 접근할 경우, :postId
에 연결된 컴포넌트가 보여지게 되고, 해당 컴포넌트에서는 주소에 명시된 1이라는 숫자를 postId 라는 이름의 변수로 사용할 수 있게 된다. 변수를 가져오는 것은 useParams
라는 Hook 이 담당하게 된다.
import { Outlet } from 'react-router-dom'
하위 컴포넌트 주소로 이동 시 하위 컴포넌트 내용을 보고 싶다면 <Outlet/>
이라는 태그를 추가해야 한다.
Index Route 는 Nested Route 구조에서, /
뒤에 아무도 없는 주소 상태일 때 보여줄 컴포넌트를 정하는 Route 를 말한다.
<Route path="posts" element={<Posts/>}>
<Route index element={<PostIndex/>}/>
<Route path=":postId" element={<PostDetail/>}/>
</Route>
이렇게 작성하면, /posts 로 접근했을 때, PostIndex 컴포넌트 내용이 보인다!
useParams는 URL 인자들의 key/value(키/값) 짝들의 객체를 반환한다. 현재
<Route>
의 match.params에 접근하기 위해 사용한다.
예시)
// App.js
<Route path=":postId" element={<PostDetail/>}/>
-> postId 라는 이름으로 값을 넘기도록 설정했다.
const params = useParams();
console.log(params) // {postId:~}
그렇기 때문에 params 안에는 postId 라는 키로 값이 담겨 있다.
import React from 'react'
import { useParams } from 'react-router-dom';
import {postData} from '../../../constants/postData'
function PostDetail() {
const params = useParams();
const post = postData.find((post) => post.id === parseInt(params.postId))
return (
<div>
{post.title}
{post.body}
</div>
)
}
export default PostDetail
{posts.map((post) => {
return (
<p key={post.id}>
<Link to={`/posts/${post.id}`} state={{ post:posts.find((data) => data.id === post.id) }}>{post.title}</Link>
</p>
)
})}
postData
를 또 불러오는게 비효율적이라고 판단, Link
를 타고 이동하면서 데이터를 넘겨주기! Link
태그에 state
명시!
import React from 'react'
import { useLocation, useParams } from 'react-router-dom';
function PostDetail() {
const params = useParams();
const location = useLocation();
const {post} = location.state
return (
<div>
{post.title}
{post.body}
</div>
)
}
export default PostDetail
이렇게 받아서 사용하기!
주소 이동을 위한 Hook, Link 와는 다르게 함수 안에서 주소 이동 동작을 실행하고자 할 때 사용한다.
import { useNavigate } from "react-router-dom"
const navigate = useNavigate()
navigate("주소", 옵션)
옵션
// 옵션 1
// 이동하면서 접근 이력을 유지할 지, 버릴 지 선택합니다.
{ replace: true }
// 옵션 2
// 주소 이동하면서 전달하고자 하는 값을 명시합니다.
{ state: 넘어가면서 전달하고자 하는 데이터 }]
뒤로가기 / 앞으로가기
navigate(숫자)
import React from 'react'
import { useLocation, useNavigate, useParams } from 'react-router-dom';
function PostDetail() {
const params = useParams();
const location = useLocation();
const navigate = useNavigate();
const {post} = location.state ? location.state : {post:''}
if (!post) return <p>Not Found</p>
return (
<div>
{post.title}
{post.body}
<button onClick={() => navigate(-2)}>뒤로 2번가기</button>
<button onClick={() => navigate(-1)}>뒤로 1번가기</button>
<button onClick={() => navigate(1)}>앞으로 1번가기</button>
<button onClick={() => navigate(2)}>앞으로 2번가기</button>
</div>
)
}
export default PostDetail