2021-04-07(수)
yarn add react-router-dom
어떤 규칙을 가진 경로에 어떠한 컴포넌트를 보여줄지 정의할 수 있다.
import { Route } from 'react-router-dom'
라우트 컴포넌트를 이용해서 라우트를 설정해준다.
<Route path="주소규칙(/login 등)" component={보여줄 컴포넌트}></Route>
// App.js
import { Route } from 'react-router-dom'
import About from './About';
import Home from './Home';
<Route path="/" component={Home}/>
<Route path="/about" component={About} />
// 이 상태로는 /about 라우트에 접근하면 Home과 About 모두 포함되어 화면에 그려진다.
// props exact=true를 설정한다.
<Route path="/" component={Home} exact={true} />
// 다중 라우트 설정하는 방법, path를 다음과 같이 설정하면 된다.
<Route path={['/about', '/info']} component={About} />
Route라고 입력하면 자동완성으로 react-router가 기본적으로 import로 추가된다.
여기서 한가지 주의할 점은 react-router-dom 모듈과 react-router은 버전 차이가 있다.
차이점은 https://blueshw.github.io/2017/06/22/static-routing-vs-dynamic-routing/ 링크를 참고.
a태그 처럼 다른 링크로 이동하는 기능을 제공하는 컴포넌트이다.
페이지를 새로 불러오지 않고 애플리케이션은 그대로 유지하고 history API를 사용해서 페이지의 주소만 변경한다.
<Link to="주소">내용</Link>
// App.js
...
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<Route path="/" component={Home} exact={true} />
<Route path={['/about', '/info']} component={About} />
// App.js
...
<li>
<Link to="/profile/kyungil">kyungil 프로필</Link>
</li>
<li>
<Link to="/profile/academy">academy 프로필</Link>
</li>
{/* match.params.username값을 통해 현재 username 조회 */}
<Route path="/profile/:username" component={Profile} />
// Profile.js
import React from 'react';
const data = {
kyungil: {
name: '놀부',
description: '욕심쟁이',
},
academy: {
name: '홍길동',
description: '동해번쩍 서해번쩍',
},
};
// URL 매개변수를 사용할 때는 라우트로 사용되는 컴포넌트에서
// 받아오는 match라는 객체안에 params 값을 참조한다.
// match안에는 현재 컴포넌트가 어떤 경로 규칙에 의해
// 보이는지에 대한 정보가 들어있다.
const Profile = ({ match }) => {
const { username } = match.params;
const profile = data[username];
if (!profile) {
return <div>사용자 없음</div>;
}
return (
<div>
<h3>
{username}({profile.name})
</h3>
<p>{profile.description}</p>
</div>
);
};
export default Profile;
http://localhost:3000/about?detail=true 링크로 결과를 확인한다.
쿼리는 location 객체에 들어있는 search 값에서 조회할 수 있다.
location객체는 라우트로 사용된 컴포넌트에게 props로 전달되고 웹 애플리케이션의 현재 주소에 대한 정보를 가지고 있다.
쿼리 스트링 모듈 설치 yarn add qs
// http://localhost:3000/about?detail=true
{
"pathname" : "/about",
"search" : "detail=true",
"hash" : ""
}
// About.js
import qs from 'qs';
function About({ location }) {
const query = qs.parse(location.search, {
ignoreQueryPrefix: true, // 문자열 맨 앞에 '?' 생략
});
// 쿼리 파싱의 결과는 문자열이다.
const showDetail = query.detail === 'true';
return (
<div>
<h1>어바웃 페이지</h1>
<p>여기는 어바웃 페이지 입니다.</p>
{showDetail && <p>디테일 값은 true</p>}
</div>
);
}
export default About;
쿼리를 쓸 때 쿼리 문자열을 객체로 파싱하는 과정에서의 결과 값은 언제나 문자열이다.
?value=1 -> ("1"), ?value=true -> ("true")
숫자를 받아와야 하는 상황에서는 parseInt 함수를 사용하고
논리 값을 사용하는 경우는 정확히 true라는 문자열이랑 일치하는지 비교한다.
http://localhost:3000/about?detail=true 주소로 들어가게되면 URL 쿼리의 결과를 확인할 수 있다.
라우트로 사용된 컴포넌트에 match, location과 함께 전달되는 props중 하나이다. history를 통해 컴포넌트 내에 구현하는 메서드에서 라우터 API를 호출할 수 있다.
예) 버튼 클릭 -> 뒤로 가기, 다른 페이지 이탈방지, 로그인 후 화면전환 ...
// HistorySample.js
import React, { Component } from 'react';
export class HistorySample extends Component {
handleGoBack = () => {
this.props.history.goBack();
};
handleGoHome = () => {
this.props.history.push('/');
};
componentDidMount() {
// 페이지에 변화가 생기려고 할 때 마다 고고씽?
this.unblock = this.props.history.block('고고씽?');
}
componentWillUnmount() {
// 컴포넌트가 언마운트되면 고고씽?을 멈춘다.
if (this.unblock) this.unblock();
}
render() {
return (
<div>
<button onClick={this.handleGoBack}>뒤로가기</button>
<button onClick={this.handleGoHome}>홈으로</button>
</div>
);
}
}
export default HistorySample;
라우트로 사용된 컴포넌트가 아니어도 location, history, match 객체에 접근할 수 있게 해준다.
import { WithRouter } from 'react-router-dom';
// WithRouterSample.js
import React from 'react';
import { withRouter } from 'react-router-dom';
// WithRouter
// 라우트로 사용된 컴포넌트가 아니어도 location, history, match 객체에 접근할 수 있게 해준다.
const WithRouterSample = ({ location, match, history }) => {
return (
<div>
<h4>로케이션</h4>
<textarea
value={JSON.stringify(location, null, 2)}
rows={7}
readOnly={true}
/>
<h4>매치</h4>
<textarea
value={JSON.stringify(match, null, 2)}
rows={7}
readOnly={true}
/>
<button onClick={() => history.push('/')}>집으로</button>
</div>
);
};
export default withRouter(WithRouterSample);
// Profile.js 파일에 아래와 같이 추가해준다.
import { withRouter } from 'react-router-dom';
import WithRouterSample from './WithRouterSample';
const Profile = ({ match }) => {
const { username } = match.params;
const profile = data[username];
if (!profile) {
return <div>사용자 없음</div>;
}
return (
<div>
<h3>
{username}({profile.name})
</h3>
<p>{profile.description}</p>
<WithRouterSample />
</div>
);
};
export default withRouter(Profile);
현재 경로와 Link에서 사용하느 경로가 일치하는 경우 특정 스타일 또는 CSS클래스를 적용할 수 있는 컴포넌트이다. NavLink에서 링크가 활성화되었을 때의 스타일을 적용할 때는 activeStyle를 사용하고, CSS 클래스를 적용할 때는 activeClassName 값을 props로 넣어준다.
import { NavLink } from 'react-router-dom';
Profiles.js에서 NavLink를 import에 추가해주고, 스타일 설정 값을 만든 후 NavLink 컴포넌트에 props activeStyle을 지정해준다.
// Profiles.js
import { Link, Route, NavLink } from 'react-router-dom';
const Profiles = () => {
const activeStyle = {
background: 'black',
color: 'white',
};
return (
<div>
<h3>사용자 목록 :</h3>
<ul>
<li>
{/* <Link to="/profiles/kyungil">kyungil</Link> */}
<NavLink activeStyle={activeStyle} to="/profiles/kyungil">
kyungil
</NavLink>
</li>
<li>
{/* <Link to="/profiles/academy">academy</Link> */}
<NavLink activeStyle={activeStyle} to="/profiles/academy">
academy
</NavLink>
</li>
</ul>
<Route
path="/profiles"
exact={true}
render={() => <div>사용자 선택</div>}
/>
<Route path="/profiles/:username" component={Profile} />
{/* <WithRouterSample /> */}
</div>
);
};