
Single Page Application의 약어
한개의 페이지로 이루어진 애플리케이션이라는 의미
다른 주소에 다른 화면을 보여주는것
앱의 규모가 커지면 자바스크립트 파일이 너무 커진다
실제로 방문하지 않을 수도 있는 페이지의 스크립트도 불러오기 때문
⇒ 코드 스필리팅을 사용하면 라우별로 파일을 나누어서 해결할수있다
리액트 라우터 처럼 브라우저의 API를 이용하게 된다면 ,JS를 사용하지 않는 일반 페이지는 정보를 제대로 수집하기 어렵다는 단점이 있다.
또한, 자바스크립트가 실행될 떄까지 페이지가 비어 있기 때문에 자바스크립트 파일이 로딩되어 실행되는 짧은 시간 동안 흰페이지가 나타날수있다는 단점이 있다
⇒ 나중에 배우게될 서버 사이드 랜더링을 통해 해결할수있다
리액트 앱 만들고
npm add react-router-dom
index.js파일에서 react-router-dom에 내장되어 있는 BrowerRouter라는 컴포넌트를 사용하여 감싼다
이 컴포넌트는
import React from 'react'
function home() {
return (
<div>
<h1>홈</h1>
<p> 홈, 그페이지느 가장 먼저 보여지는 페이지</p>
</div>
)
}
export default home
.....//.....
import React from 'react'
function About() {
return (
<div>
<h1>소개</h1>
<p> 이 프로젝트는 리액트 라우터 기초를 실습해 보는 예제 프로젝트 입니다</p>
</div>
)
}
export default About
사용자의 현재 경로에 따라 다른 컴포넌트를 보여주겠다
<Route path = "주소규착" component ={보여줄 컴포넌트}/>
App.js
import './App.css';
import { Route } from 'react-router-dom/cjs/react-router-dom.min';
import home from './home';
import About from './About';
function App() {
return (
<div>
<Route path="/" component={home} />
<Route path="/about" component={About} />
</div>
);
}
export default App;
하지만 About경로로 가면 home도 같이 나온다.?

⇒ /about 경로가 / 규칙에도 일치하기 때문이다
Home을 위한 Route 컴포넌트를 사용할때에는 exact라는 props를 true로 설정해주자
<Route path="/" component={home} exact={true} />
클릭하면 다른 주소로 이동시켜주는 컴포넌트이다
원래 일반 웹 애플리케이션에서는 a 태그를 사용하여 페이지를 전환 했는데,
리액트 라우터를 사용할 때는 이 태그를 직접 사용하면 안된다 ⇒ 페이지가 새로고침 되어서, 기존 상태가 사라짐
⇒ Link는 페이지는 유지한상태로 페이지 주소만 변경해줌
⇒ 페이지 전환을 막는 기능이 기본적으로 들어가 있음
<Link to="주소"> 내용</Link>
App.js
import './App.css';
import { Link, Route } from 'react-router-dom/cjs/react-router-dom.min';
import home from './home';
import About from './About';
function App() {
return (
<div>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">소개</Link>
</li>
</ul>
<Route path="/" component={home} exact={true} />
<Route path="/about" component={About} />
</div>
);
}
export default App;
예전에는 ?
<Route path="/" component={home} exact={true} />
<Route path="/about" component={About} />
<Route pate="/info" component={About} />
리액트 라우터 v5부터는?
<Route path="/" component={home} exact={true} />
<Route path={['/about','/info']} component={About} />
페이지 주소를 정의할때 가끔은 유동적인 값을 전달해야할때도 있다.
값을 전달해주는 방법은?
유동적인 값을 사용해야하는 상황에서 파라미터를 써야할지, 쿼리를 써야할지 규칙은 없다
다만, 일반적으로 파라미터는 특정 아이디 혹은 이름을 사용하여 조회할때 사용하고, 쿼리는 우리가 어떤 키워드를 검색하거나 페이지에 필요한 옵션을 전달할때 사용한다
Profile.js
import React from 'react'
const data = {
velopert: {
name: '김민준',
description: '리액트를 좋아하는 개발자'
},
gildong: {
name: '홍길동',
description: '고전 소설 홍길동전의 주인공'
}
}
function Profile({ match }) {
const { username } = match.params;
const profile = data[username];
const { name, description } = profile
if (!profile) {
return <div>존재하지 않는 사용자 입니다.</div>
}
return (
<div>
<h3>
{username}({name})
</h3>
<p>{description}</p>
</div>
)
}
export default Profile
/// App.js
import './App.css';
import { Link, Route } from 'react-router-dom/cjs/react-router-dom.min';
import home from './home';
import About from './About';
import Profile from './Profile';
function App() {
return (
<div>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/profile/velopert">velopert 프로필</Link>
</li>
<li>
<Link to="/profile/gildong">gildong 프로필</Link>
</li>
</ul>
<Route path="/" component={home} exact={true} />
<Route path={['/about', '/info']} component={About} />
<Route path="/profile/:username" component={Profile} />
// match.params.username값을 통해 현재 username을 조회할수 있게 된다.
</div>
);
}
export default App;

즉,변수 ⇒ 들어오는 인자를 파라미터를 통해 profile 컴포넌트로 보내주는것
쿼리는 location 객체에 들어있는 search 값에서 조회할수 있다
location의 형태
{
"pathname" : "/aboit",
"search" : "?detail=true",
"hash" : ""
}
= http://locationhost:3000/about?detail=true 주소로 들어갔을때 값
⇒ 쿼리를 이용할땐 qs라이브러리를 사용한다
yarn add qs
About.js
import React from 'react'
import qs from 'qs';
function About({ location }) { // Route 경로를 통해서 들어오는 location객체, 이중 serceh를 해석
const query = qs.parse(location.search, {
ignoreQueryPrefix: true // 이 설정을 통해서 문자열 맨앞의 ?를 생략합니다
});
const showDetail = query.detail === 'true';
return (
<div>
<h1>소개</h1>
<p> 이 프로젝트는 리액트 라우터 기초를 실습해 보는 예제 프로젝트 입니다</p>
{showDetail && <p>detail 값을 true로 설정하셨군요!</p>}
</div>
)
}
export default About
결론적으로 파람이는 쿼리이든 라우터에서 주소(경로)로 보내는주는 값을 각자 match,location 객체를 이용해서 해석해서 값을 사용할수있다.
라우트 내부에 또 라우트를 정의하는것
너무 어렵게 생각하지말고
import React from 'react'
import { Link, Route } from 'react-router-dom';
import Profile from './Profile';
function Profiles() {
return (
<div>
<h3>사용자 목록:</h3>
<ul>
<li>
<Link to="/profiles/velopert">veloport</Link>
</li>
<li>
<Link to="/profiles/gildong">gildonf</Link>
</li>
</ul>
<Route
path="profiles"
exact // 자동으로 true가 된다
render={() => <div>사용자를 선택해주세요</div>} // 보여주고 싶은 jsx를 넣어줄수 있다.
/>
<Route path="/profiles/:username" component={Profile} />
</div>
)
}
export default Profiles
//App.js
기존 App컴포넌트는 두 종류의 프로필 링크를 보여줬는데, 이거는 이를 잘래내서 프로필 링크를 보여주는 프리필 링크를 보여줌

한 컴포넌트 안에 또 라우트를 해서 컴포넌트 → 컴포넌트가 된다
라우터 API 호출해, 페이지 전환, 뒤로가기 , 페이지 이탈 방지 등에 쓰임
라우트로 사용된 컴포넌트에 match,location과 함꼐 전달되는 props중 하나이다
import React, { Component } from 'react'
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
Hoc함수이다, 라우트로 사용된 컴포넌트가 아니어도 match, location,history 객체에 접근하게 함
import React from 'react'
**import { withRouter } from 'react-router-dom'**
function WithRouterSample({ location, match, history }) {
return (
<div>
<h4>location</h4>
<textarea
value={JSON.stringify(location, null, 2)}
rows={7}
readOnly={true}
/>
<h4>match</h4>
<textarea
value={JSON.stringify(match, null, 2)}
rows={7}
readOnly={true}
/>
<button onClick={() => history.push('/')}>홈으로</button>
</div>
)
}
export default **withRouter(WithRouterSample)**

match의 params가 비어있는 이유는 현재 자신을 보여주고 있는 라우트 컴포넌트(지금은 profiles)를 기준으로 match가 전달되기 때문
⇒ 지금 profiles 라우트는 path="/profiles" 로 되어 있기 때문에 username 파라 미터를 읽어 오지 못했다(없으니깐)
여러 Router를 감싸서 그중 일치하는 단 하나의 라우트만 랜더링한다
import './App.css';
import { Link, Route, **Switch** } from 'react-router-dom/cjs/react-router-dom.min';
import home from './home';
import About from './About';
import Profiles from './Profiles';
import HistorySample from './HistorySample';
function App() {
return (
<div>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/profiles">프로필</Link>
</li>
<li>
<Link to="/history">History 예제</Link>
</li>
</ul>
**<Switch>
<Route path="/" component={home} exact={true} />
<Route path={['/about', '/info']} component={About} />
<Route path="/profiles" component={Profiles} />
<Route path="/history" component={HistorySample} />
<Route
// path를 따로 정의하지 않으면 모든 상황에 렌더링 됨// 암거나 적으면 아무것도 정의하지 않은 Path로
render={({ location }) => (
<div>
<h2>이 페이지는 존재하지 않습니다:</h2>
<p>{location.pathname}</p>
</div>
)}
/>
</Switch>**
</div>
);
}
export default App;
Link와 비슷하다. 현재 경로와 Link에서 사용하는 경로가 일치하는 경우 특정 스타일 또는 CSS 컴포넌트를 적용할수 있는 컴포넌트이다
import React from 'react'
import { Link, Route, **NavLink** } from 'react-router-dom';
import Profile from './Profile';
import WithRouterSample from './WithRouterSample';
function Profiles() {
const activeStyle = {
background: 'black',
color: 'white'
}
return (
<div>
<h3>사용자 목록:</h3>
<ul>
<li>
**<NavLink activeStyle={activeStyle} to="/profiles/velopert">veloport</NavLink>
</li>
<li>
<NavLink activeStyle={activeStyle} to="/profiles/gildong">gildonf</NavLink>
</li>**
</ul>
<WithRouterSample />
<Route
path="profiles"
exact // 자동으로 true가 된다
render={() => <div>사용자를 선택해주세요</div>} // 보여주고 싶은 jsx를 넣어줄수 있다.
/>
<Route path="/profiles/:username" component={Profile} />
</div>
)
}
export default Profiles