그냥 a태그를 사용하면 페이지 전체가 새로로딩이 된다. 흔히 말해 화면이 깜빡임이 필수적으로 발생하고 이는 사용자 경험을 떨어뜨리는 큰 요인이다. 따라서, 라우팅을 통해 부드러운 화면전환을 위해 사용된다.
npm i react-router-dom
yarn add react-router-dom
import { BrowserRouter, Routes, Route } from 'react-router-dom'
history API를 활용해 history 객체를 생성한다.
history API는 내부적으로 stack 자료구조의 형태를 띄기 때문에 사용자가 방문한 url 기록들을 차곡차곡 쌓는 형태로 저장해둔다고 생각하면 된다.
라우팅을 진행할 컴포넌트 상위에 BrowserRouter 컴포넌트를 생성하고 감싸주어야 한다.
현재 브라우저의 location(window.href.location 정보를 가져온다) 상태에 따라 다른 element를 렌더링한다.
Route.element
: 조건이 맞을 때 렌더링할 element, <Element />
의 형식으로 전달된다.
Route.path: 현재 path값이 url과 일치하는지 확인해 해당 url에 매칭된 element를 렌더링해준다.
모든 Route의 상위 경로에 존재해야 하며, location 변경 시 하위에 있는 모든 Route를 조회해 현재 location과 맞는 Route를 찾아준다!
const Router = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<GalleryPage />} />
<Route path="/gallery" element={<DetailCardPage />}>
<Route path=":cardId" element={<DetailCard />} />
</Route>
</Routes>
</BrowserRouter>
);
};
Router 컴포넌트를 생성해준 뒤, 상위 렌더링 요소에 컴포넌트를 붙인다.
import Router from "./Router";
const App = () => (
<>
<Router />
</>
);
export default App;
Link 컴포넌트는 라우터 내에서 직접적으로 페이지 이동을 하고자 할 때 사용되는 컴포넌트이다.
import React from 'react';
import {Link} from 'react-router-dom';
function Nav(){
return (
<div>
<Link to='/'> Home </Link>
<Link to='/about'> About </Link>
</div>
);
}
export default Nav;
위와 같은 방식으로 간단하게 to 속성에 경로를 넣어주는 방식으로 사용한다.
계층 구조에 상대적이다.
상대 경로 표현이 가능하므로, ./..
와 같은 표현도 사용이 가능하다.
페이지 중간에 있는 컨텐츠 내부에서 tab 목록을 누르는 것과 같은 시도를 할 때, 기존의 Link 컴포넌트였다면 클릭 시 스크롤이 초기화되어 페이지 가장 위로 이동하게 된다.
그러나 이 속성을 true로 설정해주면 이를 방지할 수 있다!!
useLocation
훅과 연계하여 특정 state를 넘겨주는 것도 가능하다.
<Link to="new-path" state={{ some: "value" }} />
let { state } = useLocation();
Link는 a태그로 이루어져 있지만, 자체적으로 컴포넌트의 상태를 유지하거나, 화면 전체 리렌더링을 방지하는 등의 기능이 포함된 a 태그의 상위 버전이라고 생각하면 좋다.
useNavigate
훅을 사용하면 특정 이벤트(onChange, onClick 등)가 발생했을 때 페이지 이동을 트리거할 수 있다.
import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
const onClick = () => {
navigate('/')
}
기본값은 false이고, true로 설정한다면 이동 후 뒤로가기가 불가능해진다.
navigate("/", { replace: true });
Link와 마찬가지로 state를 전달이 가능하다.
navigate("/", { state: { cardId: cardId } });
const location = useLocation();
const { cardId } = location.state;
V6에서 중첩 라우팅이 컴포넌트의 children과 같은 개념으로 중첨이 가능해져 더 직관적으로 변했다.
만약, /todo
와 todo/:todoId
페이지가 있다고 한다면, 이전에는 각각 한 줄씩 차지하였는데, v6에서는 todo 라우트하위에 :todoId가 포함된 Route를 추가하면 중첩 라우팅이 된다.
하위에 있으면 자동적으로 /로 구분되기 때문에 추가적인 /를 path에 추가할 필요가 없어졌다.
<Routes>
<Route path="/todo">
<Route path=":todoId" />
</Route>
</Routes>
특정 페이지들끼리 공통적으로 보여줘야 하는 레이아웃이 있을 때 유용하게 사용할 수 있다.
예를들어 Home, Detail, About페이지가 있다고 가정할 때 Detail, About페이지를 네비게이션으로 보여줘야 하는 상황일때 각 네비게이션 컴포넌트를 달아서 사용하지만, Outlet을 사용해서 한번에 호출해서 사용할 수 있다.
import { Outlet } from "react-router-dom"
export default function Layout() {
return(
<>
<nav>navigation</nav>
<Outlet />
</>
)
}
각 페이지 컴포넌트가 보여져야 하는 부분에 Outlet컴포넌트를 넣는다.
export default function App() {
return(
<BrowserRouter>
<Routes>
<Route element={<Layout />}>
<Route path="/detail" element={<Detail />} />
<Route path="/about" element={<About />} />
</Route>
<Route path="/" element={<Home />} />
</Routes>
</BrowserRouter>
)
}
실행해보면 Layout안에 Outlet영역에 각 Route에 매칭시켜놓은 element들이 렌더링 되는 것을 볼 수 있다.