react-router
다.npm install react-router-dom
프로젝트에 리액트 라우터를 적용할 때는 src/index.js
파일에서 react-router-dom
에 내장되어 있는 BroswerRouter
컴포넌트를 사용해서 루트 컴포넌트를 감싸면 된다.
BroswerRouter
컴포넌트는 웹 애플리케이션에 HRML5의 History API를 사용하여 페이지를 새로고침 하지 않고도 주소를 변경하고, 현재 주소에 관련된 정보를 props로 쉽게 조회하거나 사용할 수 있도록 해준다.
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom' // 1. import react-router-dom
import './index.css';
import App from './App';
ReactDOM.render( // 2. 루트 컴포넌트를 BrowserRouter 컴포넌트로 감싸기
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
// Router 컴포넌트 사용 방식
<Router path="주소규칙" component={보여줄 컴포넌트}/>
import React from 'react';
import { Route } from 'react-router-dom'; // Router 컴포넌트 불러오기
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<div>
<Route path="/" component={Home} exact={true}/>
<Route path="/about" component={About}/>
</div>
);
}
export default App;
Home
컴포넌트 렌더링이 되고, /about
경로로 이동시 Home
컴포넌트와 About
컴포넌트가 렌더링된다. 이는 /about
경로가 /
규칙에도 일치하기 때문이다. 이를 수정하기 위해 주소가 /
인 Router 컴포넌트에 exact
라는 props를 true
로 설정해준다.Link
컴포넌트는 클릭하면 다른 주소로 이동시켜주는 컴포넌트다. a
태그를 사용해도 페이지 전환이 되지만 그 경우 페이지를 새로 불러오기 때문에 애플리케이션이 갖고 있는 모든 상태가 초기화된다.Link
컴포넌트를 사용하여 페이지를 전환하면, 페이지를 새로 불러오지 않고 애플리케이션은 그대로 유지한 상태에서 HTML5 History API를 사용하여 페이지의 주소만 변경해준다. Link
컴포넌트 자체는 a
태그로 이루어져 있지만, 페이지 전환을 방지하는 기능이 내장되어 있다.<Link to="주소">내용</Link>
import React from 'react';
import { Route, Link } from 'react-router-dom'; // Link 컴포넌트 불러오기
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<Route path="/" component={Home} exact={true}/>
<Route path="/about" component={About}/>
</div>
);
}
export default App;
// 이전 버전 - Router 두 번 사용
<Route path="/" component={Home} exact={true}/>
<Route path="/about" component={About}/>
<Route path="/info" component={About}/>
// 최신 버전 - path props를 배열로 설정하면 여러 경로에 같은 컴포넌트를 보여줄 수 있다.
<Route path="/" component={Home} exact={true}/>
<Route path={ ['/about', '/info'] } component={About}/>
/profile/velopert
/about?detail=true
match
, location
, history
를 전달받는다. match
와 history
객체로 url 파리미터와 쿼리스트링을 처리할 수 있다.const Compnent = ({ match }) => { // match를 props로 받아옴
const { param } = match.params; // match.params에 url 파라미터에 대한 정보다 담겨있다.
}
/*
props.match = {
isExact: true
params: {username: "gyu"} => url 파라미터
path: "/profile/:username" => 경로 규칙
url: "/profile/gyu => 실제 url
}
*/"
// Route 컴포넌트
<Route path="/주소/:변수" component={컴포넌트}/>
// Link 컴포넌트
<Link to="/주소/값">내용</Link>
/*
라우트 정의 컴포넌트에서 이렇게 설정하면
url 파라미터를 받아서 처리하는 컴포넌트에서는
match.params = { 변수: 값 }로 받아 사용할 수 있다.
*/
// Profile.js
import React from 'react';
const data = {
gyu: {
name: 'Lee',
description: '코린이...'
},
gildong: {
name: '홍길동',
description: '홀길동도롱도롱롱롱롱'
}
}
const Profile = ({match}) => {
console.log(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;
// App.js
import React from 'react';
import { Route, Link } from 'react-router-dom';
import Profile from './components/Profile';
function App() {
return (
<div>
<ul>
<li>
<Link to="/profile/gyu">gyu's profile</Link>
</li>
<li>
<Link to="/profile/gildong">gildong's profile</Link>
</li>
</ul>
<Route path="/profile/:username" component={Profile}/>
</div>
);
}
// location 객체 예 - /about?detail=true
{
hash: ""
key: "wq2uka"
pathname: "/about"
search: "?detail=true"
state: undefined
}
// About.js
import React from 'react';
import qs from 'qs'; // qs 라이브러리 설치 및 불러오기
const About = ({location}) => {
const query = qs.parse(location.search, {
ignoreQueryPrefix: true // search 문자열 맨 앞의 ?를 생략하는 옵션
})
const showDetail = query.detail === 'true'; // 쿼리 파싱값은 문자열
return (
<div>
<h1>소개</h1>
<p>이 프로젝트는 리액트 라우터 기초를 실습해보는 예제 프로젝트입니다.</p>
{showDetail && <p>detail 값을 true로 설정하셨군요!</p>}
</div>
);
};
export default About;
// App.js
<Link to="/about?detail=true">About</Link>
// App.js
import React from 'react';
import { Route, Link } from 'react-router-dom';
import ProfileWrapper from './components/ProfileWrapper';
function App() {
return (
<div>
<ul>
<li>
<Link to="/profile">profiles</Link>
</li>
</ul>
<Route path="/profile" component={ProfileWrapper}/>
</div>
);
}
export default App;
// ProfileWrapper.js
import React from 'react';
import { Route, Link } from 'react-router-dom';
import Profile from './Profile'
const ProfileWrapper = () => {
return (
<div>
<h3>사용자 목록 : </h3>
<ul>
<li>
<Link to="/profile/gyu">gyu's profile</Link>
</li>
<li>
<Link to="/profile/gildong">gildong's profile</Link>
</li>
</ul>
<Route
path="/profile"
exact
render={()=><div>사용자를 선택해 주세요.</div>}
/>
<Route path="/profile/:username" component={Profile} />
</div>
);
};
export default ProfileWrapper;
/*
JSX에서 props를 설정할 때 값을 생략하면 자동으로 true로 설정된다.
때문에 exact={true}는 exact와 같다.
Route 컴포넌트에 component 대신 render라는 props를 넣었다.
render는 컴포넌트 자체가 아닌 보여주고 싶은 JSX를 반환하는 함수를 넣어
컴포넌트를 만들기 애매한 상황이나, 컴포넌트에 별도의 props를 넣어주고 싶을 때 사용한다.
*/
history.goBack() // 뒤로가기
history.push('rout') // 특정 라우트로 이동
import React from 'react';
import { withRouter } from 'react-router-dom'; // 1. withRouter 불러오기
const WithRouterSample = ({ location, match, history }) => {
return ( // 2. props로 location, match, history 받아오기
<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);
// 3. 컴포넌트를 export할 때 withRouter 함수로 감싸주기
// * JSON.stringify()함수의 두, 세번째 매개변수에 null, 2를 넣으면
// JSON에 들여쓰기 된 상태로 문자열이 생성됨
💡 고차 컴포넌트(HOC, Higher Order Component)
컴포넌트를 인자로 받아서 컴포넌트를 반환하는 함수로 컴포넌트 로직을 재사용하기 위한 React의 고급 기술이다.
import React from 'react';
import { Route, Link, Switch } from 'react-router-dom';
import About from './About';
import Home from './Home';
import Profiles from './Profiles';
import HistorySample from './HistorySample';
const 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>
<hr />
<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를 따로 정의하지 않으면 모든 상황에 렌더링됨
render={({ location }) => (
<div>
<h2>이 페이지는 존재하지 않습니다:</h2>
<p>{location.pathname}</p>
</div>
)}
/>
</Switch>
</div>
);
};
export default App;
import React from 'react';
import { NavLink, Route } from 'react-router-dom';
import Profile from './Profile';
const Profiles = () => {
const activeStyle = {
background: 'black',
color: 'white'
};
return (
<div>
<h3>사용자 목록:</h3>
<ul>
<li>
<NavLink activeStyle={activeStyle} to="/profiles/velopert" active>
velopert
</NavLink>
</li>
<li>
<NavLink activeStyle={activeStyle} to="/profiles/gildong">
gildong
</NavLink>
</li>
</ul>
<Route
path="/profiles"
exact
render={() => <div>유저를 선택해주세요.</div>}
/>
<Route path="/profiles/:username" component={Profile} />
</div>
);
};
export default Profiles;