React Router를 마스터해보자.
router를 하기전에 새로운 파일을 만들어 보자 React template를 미리 만들어놓으면 복사해서 써주면 아주 간편하기에 만들어놓는것을 추천한다. 복사하는 방법은
cp -R [복사할 폴더 or 파일][만들파일 or 폴더]
npm install react-router-dom
이지하다 좋은 스타트이다.
이제 라우팅을해보자
사용자가 어떤 주소로 들어왔을때, 그주소에 해당하는 적당한 페이지를 사용자에게 전해주는것을 라우팅 또는 라우터라 한다.
자 그렇게 설치가 끝이 났으면 import를 해주자.
import {BrowserRouter, Route} from 'react-router-dom';
BrowserRouter, 이친구는 최상위 컴포넌트이다.
그래서 만약 App이 기준컴포넌트라면
이런식으로 감싸주면된다.
Url에 따른 적당한 컴포넌트가 잘위치하게 도와주는 친구는 Route
<BrowserRouter>
<App/>
</BrowserRouter>
function App() {
const name = "jin";
return (
<div>
<h1>React Router</h1>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/about">About</a>
</li>
<li>
<a href="/contact">contact</a>
</li>
</ul>
<Route path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
</div>
);
}
export default App;
이런식으로 route에게 이동하고 싶은 path를 설정해주면된다.
클릭시, 클릭한 컴포넌트가 보이게 된다. 캬~
근데 여기서 중요한게 있다. 나는 contact를 클릭했는데, home하고 contact가 같이보이게 된다.
왜그러는것일까?
그 이유는
www.good.com/
www.good.com/contact
나의 홈의 path는 "/" contact의 path는 "/contact" 이다 이렇게되면 contact를 클릭시에 / 인 home에도 걸리게되고 contact에도 같이 걸리게된다.
<Route exact path="/">
<Home />
</Route>
이렇게만 exact만 넣어주면 그것에 정확히 맞는 것만 매칭해주기때문에 이러한 문제를 개선할수있다.
exact와 비슷한 효과를 낼수있는게 있는데, 그것은 switch이다. 하지만, 조금 다르기에 일단은 봐보자. 우선 switch도 import해주자
import {BrowserRouter, Route, Switch} from 'react-router-dom';
<Switch>
<Route path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
</Switch>
여기서 switch 로 감싸게되면 path와 일치하는 첫번째 컴포넌트를 발견하면 나머지 컴포넌트를 버린다. 따라서 여기서 exact가없으면 모두 / 가 걸려서 home이외의 나머지는 클릭을해도 출력이되지않는다.
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
그런데 만약에 home을 가장 밑으로 놓게되면 클릭시에 /이 마지막에 중복이되어서 하나클릭해도 모두 이동이 가능하게되어진다.
이러한 스위치의 특징을 이용하면 사용자가 잘못된 페이지에 접속시에 Not found라는 메시지를 출력할수있게된다.
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/">Not found</Route>
</Switch>
그런데, react의 장점인 싱글페이지에서 새로운 컴포넌트가 리로드될때 새로고침없이 보여주는 위해서는 link를 사용해야한다.
import { BrowserRouter, Route, Switch, Link } from "react-router-dom";
또 Link를 import해주고, 기존의 a태그를 Link태그로 변경하고, href를 to로 변경해주면 끝이다. 이제 리로드가 새로고침없이 되는것을 확인할수있다. 캬 정말 간편하고 좋다.
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/contact">contact</Link>
</li>
여기서 잠깐,
웹서버를 설정할때 어떤 path로 들어오던간에 root페이지에있는 html파일을 서비스할수있다면
BrowserRouter를 써야하고 그게안된다면 HashRouter를 쓰면된다.
import {HashRouter} from 'react-router-dom';
HashRouter는 대신에 url주소에 /#/ 이런식으로 #이 추가되는데 브라우저는 #를무시하기에 괜찮지만 깔끔하지는 않다.
다시 Link에 살짝 부가적인 기능이있는 Link가있는데,
NavLink이다
import {BrowserRouter, Route, Switch, NavLink} from 'react-router-dom';
클릭시에 a태그에 active라는 class가 형성되는게 보인다.
와 진짜 편하다. 이것을 이용하면, 사용자가 자신이 위치한곳을 쉽게 보여줄수있다. 엄청나다.
재밌는점은 router안에 router가 중복되서도 작동이될수있는데
만약에 about안에 switch와 Route를 이용해서 아래와 같이 만들면
<li>
<NavLink to="/about">
<h2>About</h2>
<ul>
<li>
<NavLink to="/about/1">About 1</NavLink>
<NavLink to="/about/2">About 2</NavLink>
<NavLink to="/about/3">About 3</NavLink>
</li>
</ul>
<Switch>
<Route path="/about/1">about1 입니다</Route>
<Route path="/about/2">about2 입니다</Route>
<Route path="/about/3">about3 입니다</Route>
</Switch>
</NavLink>
</li>
이런식의 결과를 만들수도있다.
그런데 페이지가 이런식으로 몇개밖에없을때는 이런식으로 하면되지만, 우리가 작업할 페이지가 수없이 많을때에는 배열을 만들어 자동으로 리스트와 라우터를 만들면된다.
class App extends Component {
state = {
lis: [],
};
hey = () => {
const contents = [
{ id: 1, title: "ok", description: "hello" },
{ id: 2, title: "ok", description: "hello" },
{ id: 3, title: "ok", description: "hello" },
];
this.setState({
lis: contents,
});
};
componentDidMount() {
this.hey();
}
render() {
const { lis } = this.state;
return (
<div>
<h1>React Router</h1>
<ul>
<li>
<NavLink to="/">Home</NavLink>
</li>
<li>
<NavLink to="/about">
<h2>About</h2>
<ul>
{lis.map((newlist) => (
<NavLink to={`/about/${newlist.id}`}>
<About
key={newlist.id}
title={newlist.title}
description={newlist.description}
></About>
</NavLink>
))}
</ul>
<Switch>
<Route path="/about/1">about1 입니다</Route>
<Route path="/about/2">about2 입니다</Route>
<Route path="/about/3">about3 입니다</Route>
</Switch>
</NavLink>
</li>
<li>
<NavLink to="/contact">contact</NavLink>
</li>
</ul>
import React, { Component } from "react";
class About extends Component {
render() {
console.log(this.props);
return (
<li>
About
<h2>{this.props.title}</h2>
<p>{this.props.description}</p>
</li>
);
}
}
export default About;
이런식으로 작성하게되면
이런식으로 배열로 리스트를 작성했을때 하나의 route로 이동하는 방법이있는데,
<Route path="/about/:about_id">
<About></About>
</Route>
이런식으로 Route path안에 :about_id 로 이동되어질 값만 입력해주면끝이다.
이외의 hook을이용한 useParams도 있고 더욱 많은 api들이있다 더욱더 알아봐서 더 좋은 서비스를 만들어보자.