Router Dom
이란 URL의 링크에 따라 Component를 생성해주는 겁니다.
React는 SPA(single page application)입니다.
물론 하나의 URL 링크로 사용자에게 페이지를 보여줄 수 있습니다.
하지만 사용자가 특정 페이지로 이동하고 싶지만, 그럴수 없게 되죠.
이때 Router Dom을 사용하는 겁니다.
💡 공식 문서 : https://reactrouter.com/en/v6.3.0/getting-started/overview
💡 참고 사이트 : https://blog.webdevsimplified.com/2022-07/react-router/
이름에서도 파악할 수 있듯이, 어떤 웹 사이트의 전체 페이지를 하나의 페이지에 담아 동적으로 화면을 바꿔가며 표현하는 것이 SPA이다. 뭔가를 클릭하거나 스크롤하면, 상호작용하기 위한 최소한의 요소만 변경이 일어난다. 페이지 변경이 일어난다고 보여지는 것 또한 최초 로드된 자바스크립트를 통해 미리 브라우저에 올라간 템플릿만 교체되는 것이다.
npm install react-router-dom@6
프로젝트에 리액트 라우터를 적용할 때는 src/index.js 파일에서 react-router-dom에 내장되어 있는 BrowserRouter라는 컴포넌트를 사용하여 감싸면 됩니다. 이 컴포넌트는 웹 애플리케이션에 HTML5의 History API를 사용하여 페이지를 새로 불러오지 않고도 주소를 변경하고 현재 주소의 경로에 관련된 정보를 리액트 컴포넌트에서 사용할 수 있도록 해 줍니다.
src/index.js
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter basename={process.env.PUBLIC_URL}>
<App />
</BrowserRouter>
</React.StrictMode>
);
💡gh-pages로 배포한 페이지가 router인식을 못하는 문제 - 빈페이지 오류 해결
<BrowserRouter basename={process.env.PUBLIC_URL}>
넣어주기
BrowserRouter에 basename props를 추가하면 프로젝트의 기본 URL을 설정해줄 수 있다. 라우터로 이동할 경우 "/"를 기준으로 이동하는 것이 아닌 "/react-sns-login/"을 기준으로 이동하는 것이다.
src/pages/Home.js
const Home = () => {
return (
<div>
<h1>홈</h1>
<p>가장 먼저 보여지는 페이지입니다.</p>
</div>
);
};
export default Home;
src/pages/About.js
const About = () => {
return (
<div>
<h1>소개</h1>
<p>리액트 라우터를 사용해 보는 프로젝트입니다.</p>
</div>
);
};
export default About;
사용자의 브라우저 주소 경로에 따라 우리가 원하는 컴포넌트를 보여주기 위해서 Route 라는 컴포넌트를 통해 라우트 설정을 해주어야 합니다.
💡
Route
컴포넌트는 사용법<Route path="주소규칙" element={보여 줄 컴포넌트 JSX} />
💡
Route
컴포넌트는Routes
컴포넌트 내부에서 사용되어야 합니다.<Routes> <Route path="주소규칙" element={보여 줄 컴포넌트 JSX} /> </Routes>
src/App.js
import { Route, Routes } from 'react-router-dom';
import About from './pages/About';
import Home from './pages/Home';
const App = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
};
export default App;
리액트 라우터를 사용하는 프로젝트에서 a
태그를 바로 사용하면 안됩니다. 왜냐하면, a
태그를 클릭하여 페이지를 이동할 때 브라우저에서는 페이지를 새로 불러오게 되기 때문입니다.
Link
컴포넌트 역시 a
태그를 사용하긴 하지만, 페이지를 새로 불러오는 것을 막고 History API를 통해 브라우저 주소의 경로만 바꾸는 기능이 내장되어 있습니다.
💡
Link
컴포넌트 사용법<Link to="경로">링크 이름</Link>
src/pages/Home.js
import { Link } from 'react-router-dom';
const Home = () => {
return (
<div>
<h1>홈</h1>
<p>가장 먼저 보여지는 페이지입니다.</p>
<Link to="/about">소개</Link>
</div>
);
};
export default Home;
useNavigate
는 Link
컴포넌트를 사용하지 않고 다른 페이지로 이동을 해야 하는 상황에 사용하는 Hook 입니다.
💡
useNavigate
컴포넌트 사용법navigate('/경로')
navigate(-1)
뒤로 1번 가기navigate(2)
앞으로 2번 가기 기능
function App(){
let navigate = useNavigate()
return (
(생략)
<button onClick={()=>{ navigate('/detail') }}>이동버튼</button>
)
}
페이지를 찾을 수 없을 때 나타나는 페이지입니다.
src/pages/NotFound.js
const NotFound = () => {
return (
<div>
없는 페이지 입니다.
</div>
);
};
export default NotFound;
src/App.js
import { Route, Routes } from 'react-router-dom';
import NotFound from './pages/NotFound';
const App = () => {
return (
<Routes>
<Route path="*" element={<NotFound />} />
</Routes>
);
};
export default App;
React Router의 가장 간단하고 일반적인 고급 기능은 동적 경로를 처리하는 것입니다. 이 예에서 응용 프로그램의 개별 책에 대한 구성 요소를 렌더링한다고 가정해 보겠습니다. 우리는 각각의 경로를 하드코딩할 수 있지만 수백 권의 책이 있거나 사용자가 책을 만들 수 있는 능력이 있다면 이 모든 경로를 하드코딩하는 것은 불가능합니다. 대신 동적 경로가 필요합니다.
예시: /profile/velopert
URL 파라미터는 주소의 경로에 유동적인 값을 넣는 형태
URL 파라미터는 ID 또는 이름을 사용하여 특정 데이터를 조회할 때 사용
src/App.js
<Routes>
<Route path="/books/:id" element={<Book />} />
</Routes>
위의 예에서 마지막 경로는 동적 매개변수가 인 동적 경로입니다
:id
. React Router에서 동적 경로를 정의하는 것은 경로의 동적 부분을 원하는 것 앞에 콜론을 넣는 것만큼 간단합니다.
우리의 경우 동적 경로는 /book
특정 값으로 시작하고 끝나는 모든 URL과 일치합니다.
예를 들어, /books/1
, /books/bookName
및 /books/literally-anything
모두 동적 경로와 일치합니다.
이와 같은 동적 경로가 있을 때 거의 항상 useParams
후크가 들어오는 사용자 지정 구성 요소의 동적 값에 액세스하려고 합니다.
src/pages/Book.js
import { useParams } from "react-router-dom"
export function Book() {
const { id } = useParams()
return (
<h1>Book {id}</h1>
)
}
후크는 매개변수를 사용 useParams
하지 않으며 경로의 동적 매개변수와 일치하는 키가 있는 객체를 반환합니다. 우리의 경우 동적 매개변수는 :id
후크 useParams
가 의 키를 가진 객체를 반환하고 해당 키 id
의 값이 URL의 실제 ID가 되도록 하는 것입니다.
예를 들어, 우리의 URL이 우리의 페이지라면 Book 3/books/3
를 렌더링할 것 입니다.
예시: /articles?page=1&keyword=react**
쿼리 스트링은 주소의 뒷부분에 ? 문자열 이후에 key=value 로 값을 정의하며 & 로 구분을 하는 형태
쿼리스트링(Querystring)은 키워드 검색, 페이지네이션, 정렬 방식 등 데이터 조회에 필요한 옵션을 전달할 때 사용
정리 필요
https://velog.io/@velopert/react-router-v6-tutorial#42-%EC%BF%BC%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A7%81
중첩된 라우트와 Outlet
은 페이지끼리 공통적으로 보여줘야 하는 레이아웃이 있을때도 유용하게 사용할 수 있습니다.
예를 들어서, Home, About, Book 페이지에서 상단에 헤더를 보여줘야 하는 상황을 가정해봅시다. 방금 배운 중첩된 라우트와 Outlet
을 활용하여 구현을 할 수 있습니다.
중첩된 라우트를 사용하는 방식을 사용하면 컴포넌트를 한번만 사용해도 된다는 장점이 있죠.
src/Layout.js
import { Outlet } from 'react-router-dom';
const Layout = () => {
return (
<div>
<header style={{ background: 'lightgray', padding: 16, fontSize: 24 }}>
Header
</header>
<main>
<Outlet />
</main>
</div>
);
};
export default Layout;
각 페이지 컴포넌트가 보여져야 하는 부분에 Outlet
컴포넌트를 사용해주었습니다.
src/App.js
import { Route, Routes } from 'react-router-dom';
import Layout from './Layout';
import About from './pages/About';
import Home from './pages/Home';
import Book from './pages/Book';
const App = () => {
return (
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/Book/:username" element={<Profile />} />
</Route>
</Routes>
);
};
export default App;
Route
컴포넌트에는 index
라는 props
가 있습니다.
이 props
는 path="/"
와 동일한 의미를 가집니다.
path="/"
와 동일한 역할을 하며 이를 좀 더 명시적으로 표현하는 방법입니다.
src/App.js
import { Route, Routes } from 'react-router-dom';
import Layout from './Layout';
import About from './pages/About';
import Home from './pages/Home';
import Book from './pages/Book';
const App = () => {
return (
<Routes>
<Route element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/Book/:username" element={<Profile />} />
</Route>
</Routes>
);
};
export default App;
basename={process.env.PUBLIC_URL} 추가
gh-pages는 SPA를 지원하지 않습니다.
그래서 배포한 곳에서 다른 경로로 이동한 뒤 새로고침을 하면 404 페이지가 뜨는 데 이를 해결할 수 있는 방법이 있습니다.