-
react-router-dom리액트 2021. 9. 15. 19:12
리액트는 안타깝게도 라우팅 기능을 내장 되어있지 않아 이를 도와줄 수 있는 라이브러리를 사용해야 합니다. 많고많은 리액트 라우터 라이브러리 중에 사람들이 가장 많이 사용하는 react-router-dom에 대하여 알아보겠습니다.
설치
먼저 새로운 프로젝트 생성 후 해당 프로젝트 디렉토리로 이동하겠습니다.
npx create-react-app router-practice cd router-practice
그 후 react-router-dom 라이브러리를 설치하겠습니다.
npm install react-router-dom
예시 1 : 기본 라우팅
import React from "react"; import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom"; export default function App() { return ( <Router> <div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/users">Users</Link> </li> </ul> </nav> {/* A <Switch> looks through its children <Route>s and renders the first one that matches the current URL. */} <Switch> <Route path="/about"> <About /> </Route> <Route path="/users"> <Users /> </Route> <Route path="/"> <Home /> </Route> </Switch> </div> </Router> ); } function Home() { return <h2>Home</h2>; } function About() { return <h2>About</h2>; } function Users() { return <h2>Users</h2>; }
위의 예시를 보시면 라우터가 3개의 페이지(home 페이지, about 페이지, users 페이지)를 처리하고 있습니다. 세개의 다른 <Links>를 클릭해보면 라우터는 <Route>에 맞는 페이지를 랜더링합니다.
위의 예시에 사용된 컴포넌트들을 자세히 보겠습니다.
Primary Components
React Router의 컴포넌트는 크게 3가지로 나눌 수 있습니다.
Routers
- <BrowserRouter>
- <HashRouter>
Route Matchers
- <Route>
- <Switch>
Navigation
- <Link>
- <NavLink>
- <Redirect>
Routers
프로젝트에 react-router을 적용하기 위해서는 엘리먼트 계층중의 root에 렌더링이 되도록 설정해야합니다. 이 때문에 대부분 아래와 같이 <App> 엘리먼트를 감싸도록 작성합니다.
src/index
import React from "react"; 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") );
<BrowserRouter>와 <HashedRouter>의 차이는 무엇일까요?
BrowserRouter
<BrowserRouter>은 우리가 흔히 사용하는 URL를 사용합니다. URL를 사용하여 서버와 소통할 수 있으며, HTML5의 History API를 사용하여 페이지를 새로고침하지 않고도 주소를 변경할 수 있습니다.
HashedRouter
그 반면 <HashedRouter>을 사용하면 URL에 http://localhost:3000/#/users 이렇게 '#(해쉬)'를 발견할 수가 있습니다. 해쉬는 서버에 보내지지 않기에 서버와의 소통이 불가합니다. 그 때문에 주로 정적인 페이지를 작성할 때 사용합니다.
Route Matchers
Route Matchers 컴포넌트에는 Switch와 Route가 있습니다. Switch 컴포넌트는 여러 Route를 감싸서 그 중 제일 처음 매칭되는 하나의 라우트만을 렌더링합니다. 만약에 맞는 Route가 없다면 Switch는 null을 렌더링합니다.
<Route path>의 특징
<Route>의 path는 전체 값이 정확히 일치하는지를 보지 않고 URL의 시작부터 매칭을 합니다. 그렇기 때문에 언제나 <Route path="/">와는 항상 매칭할 수밖에 없습니다.
띠라서 아래의 경우와 같이 <Route path="/">를 가장 위에 작성했다면 /about과 /users으로 이동이 불가능합니다.
<Switch> <Route path="/"> <Home /> </Route> <Route path="/about"> <About /> </Route> <Route path="/users"> <Users /> </Route> </Switch>;
확인해보시면 아래와 같이 작동이 안되는 것을 알 수가 있습니다.
이를 해결하기 위해 2가지 방법이 있습니다.
첫번째 방법은 exact를 사용하는 것입니다.
<Switch> <Route path="/" exact> <Home /> </Route> <Route path="/about"> <About /> </Route> <Route path="/users"> <Users /> </Route> </Switch>;
exact 속성을 주면 주어진 path값과 완벽히 일치해야 이동할 수 있도록 제한할 수 있습니다.
두번째 방법은 가장 아래에 두는 것입니다.
<Switch> <Route path="/about"> <About /> </Route> <Route path="/users"> <Users /> </Route> <Route path="/"> <Home /> </Route> </Switch>;
가장 아래에 두면 path="/"를 가장 마지막에 찾기 때문에 이를 방지할 수가 있습니다.
Navigation
<Link>
리액트 라우터는 <Link>컴포넌트를 통해 다른 주소로 이동시켜 줄 수 있는 링크를 생성할 수 있습니다. <Link> 사용 시 HTML 다큐먼트에 <a>태그를 랜더링하여 사용합니다. 그러나 우리가 흔히 사용하는 <a>태그와 다르게 페이지 전환을 방지하는 기능을 내장하고 있어 페이지를 새로 부르지 않고 페이지의 주소만 변경하도록 합니다.
<NavLink>
<NavLink>는 <Link>와 같습니다만 "active" 상태일 때 스타일링을 할 수 있는 <Link>입니다.
아래와 같이 activeClassName을 주어 active 상태일 때 해당 css가 적용할 수 있습니다.
<NavLink to="/react" activeClassName="hurray"> React </NavLink>
또는 아래와 같이 activeStyle로 직접 active 상태일 때의 css를 줄 수가 있습니다.
<NavLink to="/faq" activeStyle={{ fontWeight: "bold", color: "red" }} > FAQs </NavLink>
<Redirect>
<Redirect>는 강제로 해당 주소로 이동을 시킵니다.
<Route exact path="/"> {loggedIn ? <Redirect to="/dashboard" /> : <PublicHomePage />} </Route>
위와 같이 특정 조건에 강제로 다른 주소로 이동 시킬 때 사용할 수가 있습니다.
예시 2 : Nested 라우팅
import React from "react"; import { BrowserRouter as Router, Switch, Route, Link, useRouteMatch, useParams } from "react-router-dom"; export default function App() { return ( <Router> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/topics">Topics</Link> </li> </ul> <Switch> <Route path="/about"> <About /> </Route> <Route path="/topics"> <Topics /> </Route> <Route path="/"> <Home /> </Route> </Switch> </div> </Router> ); } function Home() { return <h2>Home</h2>; } function About() { return <h2>About</h2>; } function Topics() { let match = useRouteMatch(); return ( <div> <h2>Topics</h2> <ul> <li> <Link to={`${match.url}/components`}>Components</Link> </li> <li> <Link to={`${match.url}/props-v-state`}> Props v. State </Link> </li> </ul> {/* The Topics page has its own <Switch> with more routes that build on the /topics URL path. You can think of the 2nd <Route> here as an "index" page for all topics, or the page that is shown when no topic is selected */} <Switch> <Route path={`${match.path}/:topicId`}> <Topic /> </Route> <Route path={match.path}> <h3>Please select a topic.</h3> </Route> </Switch> </div> ); } function Topic() { let { topicId } = useParams(); return <h3>Requested topic ID: {topicId}</h3>; }
위의 예시는 Topics 함수와 Topic 함수에 주목하시면 됩니다. /Topics 라우트는 Topics 컴포넌트를 paths :id 값에 따라 조건적으로 렌더링합니다.
위에 새로 사용한 useRouteMatch와 useParams에 대하여 알아보도록 하겠습니다.
useRouteMatch()
useRouteMatch 훅을 사용하면 match 오브젝트에 손쉽게 접근할 수가 있습니다.
match는 무엇일까요?
match는 <Route path>가 어떻게 URL과 매칭이 되었는지에 관한 정보를 담은 오브젝트입니다.
match는 아래의 값을 지니고 있습니다.
- path : [string] 매칭에 사용된 path 패턴
- url : [string] 매칭에 사용된 url 부분
- isExact : [boolean] 전체 경로가 완전히 매칭할 때 true 반환
- params : [JSON object] url path로 전달된 파라미터 객체
덕분에 match 오브젝트를 통해 url 및 파라미터 값을 손쉽게 접근할 수 있습니다.
사실 match와 같은 부가적인 정보를 지닌 오브젝트는 2개 더 있습니다. 위의 예제와 상관없지만 react-router을 구성하는 중요 오브젝트들이니 알아보도록 하겠습니다.
history
history 오브젝트는 현재까지 이동한 경로를 저장한 오브젝트입니다. 해당 오브젝트를 통해 특정 버튼을 눌렀을 시 뒤로 가거나, 로그인 후 화면을 전환할 때 등에 history를 활용할 수가 있습니다.
hisory는 아래의 값을 지닙니다.
- length : [number] 전체 history 스택의 길이
- action : [string] 최근에 수행된 action (PUSH, REPLACE or POP)
- location : [JSON object] 최근 경로 정보
- push(path, [state]) : [function] 새로운 경로를 history 스택으로 푸시하여 페이지를 이동
- replace(path, [state]) : [function] 최근 경로를 history 스택에서 교체하여 페이지를 이동
- go(n) : [function] : history 스택의 포인터를 n번째로 이동
- goBack() : [function] 이전 페이지로 이동
- goForward() : [function] 앞 페이지로 이동
- block(prompt) : [function] history 스택의 PUSH/POP 동작을 제어
사용예시
- block 메서드를 통하여 해당 페이지를 떠날 시 '정말로 떠나겠습니까?'와 같은 문구가 나타나도록 할 수 있습니다.
- push 메서드를 통하여 다른 경로로 이동할 수 있습니다.
- goBack goForward 메서드를 통해 전 후 페이지를 다시 찾아 갈 수 있습니다.
Hook
let history = useHistory();
history 또한 match와 마찬가지로 훅을 통해 접근할 수가 있습니다.
location
location 오브젝트는 현재 페이지에 대한 정보를 지닙니다.
location은 아래의 값을 지닙니다.
- pathname : [string] 현재 페이지의 경로명
- search : [string] 현재 페이지의 query string
- hash : [string] 현재 페이지의 hash
사용예시
- location은 아래와 같이 <Link to>에 사용도 가능하며 history에 location 값을 넣을 때도 사용합니다.
const location = { pathname: '/somewhere', state: { fromDashboard: true } } <Link to={location}/> <Redirect to={location}/> history.push(location) history.replace(location)
Hook
let location = useLocation();
location 또한 useLocation() 훅을 통해 접근할 수가 있습니다.
useParams()
useParams() 훅은 url 파라미터를 key/value 페어 형태인 오브젝트를 반환합니다.
참고자료
'리액트' 카테고리의 다른 글
[넘블 챌린지] 색깔 찾기 게임 만들기 (0) 2022.02.13 클래스101 클론 후기 (0) 2022.01.16 ref & useRef() & forwardRef() (0) 2021.09.11 Portals (0) 2021.09.08 Context (0) 2021.09.05