개요
react-router-dom 은 새로고침 없이 URL 주소에 따라 다른 화면을 렌더링해주는 패키지이다.
Quick Start : https://reactrouter.com/web/guides/quick-start
설치
npm i react-router-dom
사용법
import {HashRouter, Route} from "react-router-dom";
<HashRouter>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</HashRouter>
Router 내부에 여러 Route들을 포함하는 구조이다.
(Hash or Browser) Router는 History API를 이용하여 새로고침 없이 주소 변경이 가능하게 해준다.
Route는 path 속성에 url를 지정하고, 그 경로에 접근시 렌더링할 구문 또는 컴포넌트를 지정할 수 있다.
- path="경로"
- component={경로접근시 렌더링할 컴포넌트}
동작 방식
<v5>
실제 코드에 작성된 순서대로 Route path와 현재 url 경로와 비교한다.
아래 구문의 의미는 url 경로상에 "/"가 있다면 component 내용을 렌더링한다는 뜻이다.
<Route path="/" component={Home} />
url 경로가 /about으로 주어진 경우 /도 만족하고 /about도 만족하므로 둘 다 렌더링 된다.
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<v6>
버전 6에서는 상당히 많이 달라졌다.
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
기본적으로 정확히 일치해야 라우팅되도록 변경됨
따라서 아래와 같이 /* 로 작성해줘야
url 경로가 /about으로 주어진 경우 /도 만족하고 /about도 만족하므로 둘 다 렌더링 된다.
<Route path="/*" element={<Home />} />
<Route path="/about" element={<About />} />
경로가 정확히 일치하는 경우에만 렌더링하기
<v5>
exact={true} 또는 exact 를 추가해주면 정확히 경로가 일치하는 경우에만 렌더링된다.
※ 그냥 exact만 써도 된다.
아래 예시는 /에 exact가 있으므로 url 경로가 /about 이더라도 /는 무시한다.
<Route path="/" exact={true} component={Home} />
<Route path="/about" component={About} />
이 방법이 불편하다면 Switch를 사용하면된다.
Switch로 감싸진 Route 중 처음으로 매칭되는 Route만 렌더링해준다.
import {Switch} from "react-router-dom";
<HashRouter>
<Switch>
<Route>
...
</Switch>
</HashRouter>
<v6>
exact 가 사라졌다.
기본적으로 정확히 일치해야 라우팅되도록 변경되었다.
Switch의 이름은 Routes로 변경되었다.
화면의 일부만 바꿔 랜더링하기
<v5>
예를 들어 모든 화면에서 <header>와 <footer>는 똑같이 렌더링되는 경우에는
url 경로가 바뀌어도 굳이 이것들을 다시 렌더링을 할 필요가 없다. 바뀔 부분만 다시 렌더링되면 된다.
<Router> 외부에 고정시킬 컴포넌트를 작성하고
<Router> 내부에 유동적으로 보여줄 컴포넌트를 Route 경로와 함께 작성한다.
<>
<header/>
<HashRouter>
<Route path="/" exact={true} component={Home} />
<Route path="/about" component={About} />
</HashRouter>
<footer/>
</>
변수가 들어간 경로 사용
<v5>
고유 식별자인 id값을 가지는 여러 요소(제목, 이미지, 영화...)들이 있을때
해당 요소를 클릭하면 그 요소에 대한 상세 정보를 보여주는 화면을 만든다고 가정하자.
상세정보를 보여주는 화면의 경로는 /about1, /about23 처럼 특정 경로 아래에 고유 식별자가 붙은 형태가 될 것이다.
이 경우 Route path에 :id 값으로 표현해줄 수 있다.
<HashRouter>
<Route path="/about/:id" component={About} />
</HashRouter>
<v6>
링크 (a tag) 사용하고 싶은 경우
HTML 에서는 <a href=""~/>를 사용하면 링크를 만들 수 있었다.
(HTML 방식)
<a href="/">Home</a>
<a href="/about">About</a>
그러나 리액트에서 a Tag 를 쓰면 안된다.
a Tag를 통해 링크를 클릭하는 순간 새 페이지를 불러오는데
리액트 앱이 가진 상태가 초기화되고 랜더링된 컴포넌트들이 모두 날라가버린다.
내가 이해한 바로는 아래와 같다.
- 쌩 HTML로만 로드하는 기존 방식은 매우 느리다.
- 리액트는 빈 HTML을 빠르게 로드한 뒤 JS로 만든 HTML을 Virtual DOM에 밀어넣어서 기존 방식보다 아주 빠르게 랜더링할 수 있다.
- 리액트는 새 페이지를 로드하지 않고 하나의 페이지 안에서만 동적으로 화면을 바꿔가며 표현하므로 새 페이지를 로드할 때의 부하가 없다. 그래서 기존 방식보다 매우 효율적이다.
- a tag 를 사용하면 새 페이지를 로드해버리므로 리액트를 쓰는 의미가 없다.
대신에 Link 라는 것을 사용해야한다.
(HTML 방식)
<a href="/">Home</a>
<a href="/about">About</a>
(React 방식)
import { Link } from "react-router-dom";
<Link to="/">Home</Link>
<Link to="/about">About</Link>
라우터에서 사용하는 객체를 컴포넌트에서 props로 넘겨받기
match, location, history props를 컴포넌트에 전달한다.
이 객체 정보를 통해 컴포넌트 자신이 어느 경로인지 알 수 있게 해준다.
경로에 따라 다른 화면을 보여주는 식으로 활용할 수 있다.
ex)
location.pathname : 현재위치
라우팅시 컴포넌트에 정보 넘겨주기
state : {} 로 컴포넌트에 정보를 넘겨줄 수 있다.
주의점 1
link to="문자열"이 아니라
link to={객체} 이렇게 작성해야하는 차이점이 있다.
<Link to={{ pathname: "/about", state: { fromNavigation: true, }, }} >
주의점 2
state가 없는 상태의 페이지도 핸들링 해줘야 한다.
클래스형 컴포넌트 사용시
컴포넌트 마운트 직후 state가 없으면 /로 되돌아가도록 제어하는 예시
componentDidMount() {
const { location, history } = this.props;
if (location.state === undefined) {
history.push("/");
}
}
render() {
const { location } = this.props;
if (location.state) {
return <span>{location.state.title}</span>;
} else {
return null;
}
컴포넌트에서 현재 페이지 정보 가져오기
<v5>
withRouter
라우터에 의해 호출된 컴포넌트가 아니더라도 match, location, history 를 props로 전달 해준다.
- this.props.match.params : 현재 페이지 경로에 포함된 파라미터값
- this.props.location.pathname : 현재 페이지 경로
- this.props.history : 페이지 변경가능 (뒤로/앞으로/특정페이지)
const {
match: { params: { id }},
history: { push },
location: { pathname },
} = this.props;
주소에 관계없이 항상 화면에 보여지는 고정형 컴포넌트(Header/Footer)에 현재 주소 등의 정보를 전달해야할 때 사용할 수 있다. 예를 들면 a화면에 접근시 Header가 a화면임을 인지하고 그에 알맞은 스타일을 보여준다거나 하는 식으로 사용될 수 있다.
Header 컴포넌트를 예시로 들어보자.
[Router.js]
export default () => (
<HashRouter>
<Header />
<Switch>
<Route path="/" exact component={Home} />
...
</Switch>
</HashRouter>
);
[Header.js]
withRouter로 컴포넌트형 함수를 감싸주면
호출시 아무정보를 받은적 없음에도 {match, location, history} = props 에 접근이 가능하다.
import { withRouter } from 'react-router-dom';
const HeaderC = ({ location: { pathname } }) => (
<Header>
<List>
<Item current={pathname === "/"}>
<SLink to="/">Movies</SLink>
</Item>
<Item current={pathname === "/search"}>
<SLink to="/search">Search</SLink>
</Item>
</List>
</Header>
);
export default withRouter(HeaderC);
<v6>
버전6에서는 withRouter가 없다. 대신 hook으로 구현하면 된다.
- useParams: 현재 페이지 경로에 포함된 파라미터값
- useLocation : 현재 페이지 경로 - URL이 달라질 때마다 이벤트가 호출 됨
- useNavigate : 페이지 변경가능 (뒤로/앞으로/특정페이지)
→ 참고로 v5에서는 useHistory 라는 이름이다.
import { useParams, useLocation, useNavigation } from "react-router-dom";
const params = useParams(); // params.id 이런식으로 파라미터 접근
const location = useLocation(); // location.pathname 이런식으로 주소접근
const navigate = useNavigate(); // navigate('/') 이런식으로 이동
useHistory vs useNavigate 비교
<v5> useHistory
const history = useHistory();
history.push('/home');
history.replace('/home');
<v6> useNavigate
버전6에서 명칭과 사용법이 약간 변경되었다.
const navigate = useNavigate();
navigate('/home');
navigate('/home', {replace: true});
<button onClick={() => navigate(-1)}>Go back</button>
<button onClick={() => navigate(1)}>Go forward</button>
라우터 종류
<HashRouter>
주소에 /#/ 같은게 붙는다. 이뻐보이지 않지만 간단하다.
웹사이트에 있다는 느낌이 아니라 앱에 있다는 느낌을 준다.
import { HashRouter, Route } from "react-router-dom";
<HashRouter>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</HashRouter>
<BrowserRouter>
평소에 보던 일반적인 주소처럼 보인다.
※ git page를 배포할 생각이라면 경로를 정확히 설정하기 귀찮으므로 HashRouter 사용 추천한다.
import { BrowserRouter, Route } from "react-router-dom";
<BrowserRouter>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</BrowserRouter>
'프론트엔드 개발 > 라이브러리' 카테고리의 다른 글
styled components 사용 방법 (0) | 2021.11.20 |
---|---|
리액트 라이브러리 gh-pages 깃 페이지 배포하기 (0) | 2021.10.02 |