리액트를 다루는 기술07

react-router

yarn add react-router-dom

NODE_PATH 설정

package.json에서 노드 패스를 설정해준다.

1
2
3
4
5
"scripts": {
"start": "NODE_PATH=src react-scripts start",
"build": "NODE_PATH=src react-scripts build"
(...)
}

window의 경우, cross-env 의존설정을 해준다.

1
2
3
4
5
"scripts": {
"start": "cross-env NODE_PATH=src react-scripts start",
"build": "cross-env NODE_PATH=src react-scripts build"
(...)
}

최상위 컴포넌트를 Root.js로 바꾸고, 기존 App.js를 감싼다.

1
2
3
4
5
6
7
8
9
10
11
12
13
import React from 'react';
import {BrowserRouter} from 'react-router-dom';
import App from './App';

const Root = () => {
return (
<BrowserRouter>
<App />
</BrowserRouter>
);
};

export default Root;

App.js에서 라우터 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react';
import {Route} from 'react-router-dom';
import {Home, About} from 'pages';
/*
pages/index.js에서는
export {default as Home} from './Home';
export {default as About} from './About';
처리
*/

const App = () => {
return (
<div>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</div>
);
};

export default App;

exact 키워드

path가 정확하게 일치할 때 보여주기 위해 사용.

만약 위의 코드에서 exact을 사용하지 않았더라면, 모든 페이지는 /이 포함되므로 모두 다 보였을 것

라우트 경로에 특정 값 넣기

params

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from 'react';
import {Route} from 'react-router-dom';
import {Home, About} from 'pages';

const App = () => {
return (
<div>
<Route exact path="/" component={Home} />
<Route path="/about/:name?" component={About} />
</div>
);
};

export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from 'react';

const About = ({match}) => {
return (
<div>
<h2>소개</h2>
<p>
안녕하세요, 저는 {match.params.name}입니다.
</p>
</div>
);
};

export default About;

만약 localhost:3000/about/react로 접속했다면,

안녕하세요, 저는 react입니다. 라는 글자가 출력될 것

localhost:3000/about만 친다면 저는 입니다, 만 나온다.

Query String

yarn add query-string

라우트 내부에서 설정해준다

해당 값들은 전부 String 형태의 값임에 유의한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from 'react';
import queryString from 'query-string';

const About = ({location, match}) => {
const query = queryString.parse(location.search);
const {color} = query;
return (
<div>
<h2 style={{color}}>소개</h2>
<p>
안녕하세요, 저는 {match.params.name}입니다.
</p>
</div>
);
};

export default About;

만약 url을 localhost:3000/about/react?color=red라고 타이핑해 접근한다면,

콘솔에는 color라는 키와 그 키 값으로 red가 들어있는 객체가 찍힌다.

위의 소스는 이를 이용해서 style을 정의한 것

라우트 이동

애플리케이션에서 다른 라우트로 이동할 때는, a 링크를 사용하면 페이지를 새로고침하면서 로딩하기 때문에 사용이 불가하다.

때문에 리액트 라우터 안에 있는 Link 컴포넌트들을 이용해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';
import {Link} from 'react-router-dom';

const Menu = () => {
return (
<div>
<ul>
<li><Link to="/"></Link></li>
<li><Link to="/about">소개</Link></li>
<li><Link to="/about/react">React 소개</Link></li>
</ul>
</div>
);
};

export default Menu;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';
import {Route} from 'react-router-dom';
import {Home, About} from 'pages';
import Menu from 'components/Menu';

const App = () => {
return (
<div>
<Menu/>
<Route exact path="/" component={Home} />
<Route path="/about/:name?" component={About} />
</div>
);
};

export default App;

Link와 거의 유사한 기능이지만, 현재 주소와 해당 컴포넌트의 목적지 주소가 일치한다면 특정 스타일 또는 클래스를 지정할 수 있다. 즉 active 표시 가능

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react';
import {NavLink} from 'react-router-dom';

const Menu = () => {
const activeStyle = {
color : 'green',
fontSize: '2rem'
};
return (
<div>
<ul>
<li><NavLink exact to="/" activeStyle={activeStyle}></NavLink></li>
<li><NavLink exact to="/about" activeStyle={activeStyle}>소개</NavLink></li>
<li><NavLink to="/about/react" activeStyle={activeStyle}>React 소개</NavLink></li>
</ul>
</div>
);
};

export default Menu;

CSS를 적용하길 원한다면 activeClassName 값을 지정해준다.

javascript를 이용한 이동

로그인 같이 특정 경로로 이동을 시켜줘야 할 때 쓰는 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';

const Home = ({ history }) => {
return (
<div>
<h2>홈</h2>
<button onClick={() => {
history.push('/about/javascript')
}}>
이동
</button>
</div>
);
};

export default Home;

라우트 안의 라우트

1
2
3
4
5
6
7
8
9
10
11
12
// 안의 라우트
import React from 'react';

const Post = ({ match }) => {
return (
<p>
포스트 #{match.params.id}
</p>
);
};

export default Post;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 밖의 라우트
import React from 'react';
import {Post} from 'pages';
import {Link, Route} from 'react-router-dom';

const Posts = ({match}) => {
return (
<div>
<h3>포스트 목록</h3>
<ul>
<li><Link to={`${match.url}/1`}>포스트 #1</Link></li>
<li><Link to={`${match.url}/2`}>포스트 #2</Link></li>
<li><Link to={`${match.url}/3`}>포스트 #3</Link></li>
</ul>
<Route exact path={match.url} render={()=>(<p>포스트를 선택하세요</p>)}/>
<Route exact path={`${match.url}/:id`} component={Post}/>
</div>
);
};

export default Posts;

location, match, history

location

1
2
3
4
5
6
{
"pathname" : "/posts/3",
"search" : "",
"hash" : "",
"key" : "xmsczi"
}

search 값에서 URL Query를 읽는데 사용하거나 주소를 바뀐 것을 감지하는데 사용

1
2
3
4
5
componentDidUpdate(prevProps, prevState) {
if(prevProps.location !== this.props.location) {

}
}

match

Route 컴포넌트에서 설정한 path와 관련된 데이터들을 조회할 때 사용

주로 prams를 조회하거나 서브 라우트를 만들 때 현재 path를 참조하는데 사용

url이 같아도 다른 라우트에서 사용된 match는 다른 정보를 알려준다.

1
2
3
4
5
6
7
8
9
{
isExact : true,
params: {
id : "2"
},
path: "/posts:id",
url: "/posts/2",
(...)
}

history

현재 라우터를 조작할 때 사용

  • push('~') : 페이지 방문 기록 남음,
  • replace(~) : 페이지 방문 기록 남지 않음, 페이지 이동 후 뒤로가기 버튼을 누르면 방금 전의 페이지가 아니라 방금 전의 전 페이지가 나타남