해당 내용은 react router v5의 내용을 담고 있습니다.
사용자가 요청한 URL에 따라 해당 URL에 맞는 컴포넌트를 보여주는 것 입니다. 다양한 라우팅 관련 라이브러리가 존재하지만 이중 가장 많이 쓰이는 것은 리액트 라우티(React Router) 입니다.
사용자가 입력한 주소를 감지해주는 래퍼 컴포넌트로써, 이후 해당 컴포넌트의 자식 컴포넌트들은 래퍼 컴포넌트가 설정한 URL에서 렌더링 됩니다.
<BrowserRouter>
는 이후 쓰일 <Route>
, <Routes>
컴포넌트들의 최상단 부모 컴포넌트입니다.
// index.js
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
path 속성에 해당 경로를 넣으면, 이후 경로를 통해 <Route>
태그안에 속하는 컴포넌트를 렌더링 합니다.
import { Route } from "react-router-dom";
import Welcome from "./pages/Welcome";
import Products from "./pages/Products";
import MainHeader from "./components/MainHeader";
import ProductDetail from "./pages/ProductDetail";
function App() {
return (
<div>
<header>
<MainHeader></MainHeader>
</header>
<main>
<Route path="/welcome">
<Welcome />
</Route>
<Route path="/products">
<Products />
</Route>
<Route path="/product-detail/">
<ProductDetail />
</Route>
</main>
</div>
);
}
<Link>
이전에 네비게이션 바에 주로 사용되었던 <a.href>
의 페이지 요청을 새로고침 없이 지원해주는 기능입니다.
<NavLink>
는 <Link>
기능과 함께 요청을 통해 해당 페이지로 성공적으로 이동이 된 경우 해당 nav 버튼에 클래스를 추가하는 activeClassName
속성을 제공합니다.
css 에서 해당 태그 .active 된 경우 적용할 기능을 추가하는 것이 가능하겠죠?!
import { NavLink } from "react-router-dom";
import classes from "./MainHeader.module.css";
const MainHeader = () => {
return (
<header className={classes.header}>
<nav>
<ul>
<li>
<NavLink activeClassName={classes.active} to="/welcome">
Welcome
</NavLink>
</li>
<li>
<NavLink activeClassName={classes.active} to="/products">
products
</NavLink>
</li>
</ul>
</nav>
</header>
);
};
export default MainHeader;
값이 정해지지 않은 동적 경로를 만들고 싶다면 해당 경로에 : 을 붙여줍니다.
...
...
<Route path="/products/:productId">
<ProductDetail />
</Route>
해당 param 값이 필요한 경우 useParam을 사용하면 가능합니다.
import { useParams } from "react-router-dom";
const ProductDetail = () => {
// /product-detail/:productId/:productNum...
const params = useParams();
console.log(params.productId);
return (
<section>
<h1>Product Detail</h1>
<p>{params.productId}</p>
</section>
);
};
export default ProductDetail;
이러한 네비게이션 바가 있다고 해봅시다.
const App = () => {
return (
<div>
<Route path="/" component={Home} />
<Route path="/movies" component={Movies} />
<Route path="/reviews" component={Reviews} />
</div>
);
};
이 경우 해당 네비게이션 바는 3가지 페이지 이동 모두 공통적으로 Home 컴포넌트를 렌더링 합니다.
우리가 흔히 쓰는 폴더 경로를 생각하시면 간단합니다. "/" 좌표는 다른 좌표들이 넘어가기전 반드시 먼저 통과해야하는 좌표이기 때문이고 <Route>
태그는 해당 페이지 요청에 맞는 컴포넌트를 렌더링 하기 때문에, 3개의 좌표 모두가 Home 컴포넌트가 렌더링 되는 것 입니다.
Switch는 Route로 생성된 자신의 자식 컴포넌트 가운데 먼저 매칭되는 한가지만을 반환합니다.
const App = () => {
return (
<div>
<Switch>
<Route path="/" component={Home} />
<Route path="/movies" component={Movies} />
<Route path="/reviews" component={Reviews} />
<Switch />
</div>
);
};
다만 이러한 경우 Home 컴포넌트만 계속 나타나게 됩니다. Switch 우선순위는 위에서 아래로 적용이 되는데, 가장 높이 "/" 루트가 있기 때문에 Home 컴포넌트 하나만 렌더링이 되는 거죠.
이 때는 위 아래 <Route>
컴포넌트 끼리 위치를 바꾸던가 혹은 정확한 경로 값이 나타날때만 렌더링이 되는 exact를 prop으로 넣어주면 문제가 해결됩니다.
const App = () => {
return (
<div>
<Switch>
<Route path="/" component={Home} exact />
<Route path="/movies" component={Movies} />
<Route path="/reviews" component={Reviews} />
<Switch />
</div>
);
};
예를 들어 게시물 목록이 그대로 렌더링 된 상태에서
해당 게시글 상세페이지를 함께 렌더링 하려고 한다.
방법이 없을까??
현재 렌더링하고 있는 <Route>
컴포넌트를 그대로 렌더링한 상태로, 필요한 목록에 대한 상세 설명 컴포넌트를 렌더링 하는 방법은, <Route>
컴포넌트 안에, 현재 <Route>
경로를 내포한, 또 하나의 <Route>
컴포넌트를 설계하면 가능하다.
// App.js
import { Route, Switch, Redirect } from "react-router-dom";
import AllQuotes from "./pages/AllQuotes";
import QuoteDetail from "./pages/QuoteDetail";
import NewQuotes from "./pages/NewQuotes";
function App() {
return (
<Switch>
<Route path="/" exact>
<Redirect to="/quotes" />
</Route>
<Route path="/quotes" exact>
<AllQuotes />
</Route>
<Route path="/quotes/:quoteId">
<QuoteDetail />
</Route>
<Route path="/new-quote">
<NewQuotes />
</Route>
</Switch>
);
}
export default App;
//QuoteDetail.js
import { useParams, Route } from "react-router-dom";
import React from "react";
import Comment from "../components/comments/Comments";
const QuoteDetail = () => {
const params = useParams();
return (
<>
<h1>Quotes Detail Page</h1>
<p>{params.quoteId}</p>
<Route path={`comments`}>
<Comment></Comment>
</Route>
</>
);
};
export default QuoteDetail;
기존의 요청을 그대로 한 체 응답으로 새로운 요청을 하도록 하여, 기존의 페이지가 아닌 제3의 페이지로 이동되는 것을 리다이렉트 라고 합니다.
가령 로그인을 해야만, 들어갈 수 있는 페이지에 사용자가 로그인 없이 들어가려고 할 때, 해당 페이지가 아닌 로그인 페이지로 보내는 것이 리다이렉트에 해당하는 예 입니다.
react-router 에서 리다이렉트를 하는 방법은, <Redirect>
를 불러와 써준 뒤, to 속성에 다른 곳으로 이동하기를 원하는 경로값을 써주면 됩니다.
// 사용자가 "/" 경로에 접근하려고 하는 경우
// quotes 페이지로 자동 이동하게 끔 만들고 싶을 때
import { Route, Redirect } from "react-router-dom";
...
...
<Route path="/" exact>
<Redirect to="/quotes" />
</Route>