지난 포스팅에 이어 react-router를 계속 이어가보도록 하겠습니다.


Route props


우선 Route의 props를 살펴보기전에 parameter부터 살펴보도록 하겠습니다.


part1 에서 사용했던 프로젝트의 containers 폴더에


post.tsx 를 새로 생성하고, 함수형 컴포넌트를 작성해주세요.


그리고 App.tsx에 Post와 Link를 삽입해주시기 바랍니다.


src/contatiners/Post

import * as React from 'react';

const Post = () => {
return (
<h1>Post - func Component</h1>
);
};

export default Post;


src/containers/index.tsx

import App from './App';
import Home from './Home';
import About from './About';
import Post from './Post';

export { App, Home, About, Post };



src/containers/App.tsx

import * as React from 'react';
import './App.css';

import { BrowserRouter as Router, Route, Link } from 'react-router-dom';

import { Home, About, Post } from '.';

const logo = require('./logo.svg');

class App extends React.Component<{}, {}> {
render() {
return (
<Router>
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/post">Post</Link>
</li>
</ul>
</nav>
<Route exact={true} path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/post/:postId" component={Post} />
</div>
</Router>
);
}
}

export default App;


post의 path에 :postId 가 추가되어있는것을 볼수 있는데요,

이것을 parameter라고 부릅니다.

간단히 애기하면 Url을 통해 넘겨지는 값이라고 생각하시면 편할것 같습니다.


일단 프로젝트 실행후

localhost:3000/post/1 주소로 접속해보겠습니다.



Post component가 렌더링 된것을 확인할수 있습니다.

그렇다면 /1 이라고 보낸 postId parameter는 어디로 간것일까요?


react dev tool 로 확인해보도록 하겠습니다.



생성된 Post component에 3개의 props가 있는것을 확인할수 있습니다.


그중 match를 먼저 살펴보면



params에 postId를 확인할수 있습니다.


그럼 이제 postId를 화면의 띄워보겠습니다.


Post.tsx를 수정해주세요.


import * as React from 'react';
import { RouteComponentProps } from 'react-router-dom';

const Post = (props: RouteComponentProps<{ postId: string}>) => {
return (
<p>post {props.match.params.postId}</p>
);
};
export default Post;

컴포넌트에서 Route를 통해 들어온 props를 사용하기 위해서는 RouteComponentPorps라는것을 사용해주어야 합니다.


따라서 Props에 정의해주고, postId가 string임을 알려줍니다. ( typesciprt니까...)


그리고 이번에는 렌더를 props.match.params.postId로 하여 parameter값을 확인할수 있게 합니다.


저장하고 실행해보겠습니다.



이전처럼 postId에 1을 넣으면 1값이 나오고, 이상한 값을 넣어도 제대로 렌더링이 되는것을 확인할수 있습니다.


이런식으로 parameter를 얻어올수 있습니다.


이번에는 다른 props를 사용하는 예제를 살펴보겠습니다.


NextPost 라는 예제입니다.


Post component에 버튼을 추가해보록 하겠습니다.


import * as React from 'react';
import { RouteComponentProps } from 'react-router-dom';

const Post = (props: RouteComponentProps<{ postId: string}>) => {
function goNextPost() {
const currPostId = props.match.params.postId;
const nextPostId = +props.match.params.postId + 1 + '';
const { pathname } = props.location;
const nextPath = pathname.replace(currPostId, nextPostId);
props.history.replace(nextPath);
}
return (
<div>
<h3>Post {props.match.params.postId}</h3>
<p>{new URLSearchParams(props.location.search).get('body')}</p>
<button onClick={goNextPost}>Next post</button>
</div>
);
};

export default Post;


params에는 숫자만 들어온다고 가정하고 만든 goNextPost 함수입니다.


버튼을 누르면 paramId가 1씩 증가되는 버튼으로


함수를 살펴보겠습니다.


currPostId 에서는 현재의 postId 값을 받아옵니다.

nextPostId 는 증가된 값을 가져오는데, props.match.params.postId 앞에 + 를 붙여준 이유는

string 값으로 들어오기때문에 강제적으로 number로 바꿔주기 위해서입니다. ( 꼼수입니다 )

props.location에서 현재 pathname을 가져온뒤 replace 함수를 사용하여 주소를 바꿔줍니다.

그리고 히스토리도 바꿔줍니다.


물론 이것보다 더 간단하게 구현할수도 있습니다.


import * as React from 'react';
import { RouteComponentProps } from 'react-router-dom';

const Post = (props: RouteComponentProps<{ postId: string}>) => {
function nextPost() {
const next = +props.match.params.postId + 1;
props.history.push(`/post/${next}`);
}
return (
<div>
<h1>post {props.match.params.postId}</h1>
<button onClick={nextPost}>nextPost</button>
</div>
);
};

export default Post;


이렇게 하면 더 간단하게 구현 가능하지만,


방법은 여러가지이므로 여러방법을 시도해보시는것을 추천드립니다.


-> prop를 여러 방면에서 다뤄보고 좀더 포스팅을 업데이트 하겠습니다.



* props.history의 replace와 push의 차이입니다.

import * as React from 'react';
import { RouteComponentProps } from 'react-router-dom';

const Post = (props: RouteComponentProps<{ postId: string}>) => {
function goNextPost() {
const currPostId = props.match.params.postId;
const nextPostId = +props.match.params.postId + 1 + '';
const { pathname } = props.location;
const nextPath = pathname.replace(currPostId, nextPostId);
props.history.replace(nextPath);
}
return (
<div>
<h3>Post {props.match.params.postId}</h3>
<button onClick={goNextPost}>Next post</button>
</div>
);
};
export default Post;


이렇게 작성된 Post component 를 실행했을때,


props.history.replace(nextPath);

여기서 replace를 

props.history.push(nextPath);

push로 바꿨을때의 차이점은


처음에 실행하였을때는 알수 없습니다.


하지만 버튼을 여러번 눌러본뒤 브라우져의 뒤로가기 버튼을 눌러보세요.


replace는 버튼을 누르기 전으로 되돌아가지만, push는 이전 버튼을 누르기 전으로 돌아갑니다.


즉 history를 가지고 있는가 없는가의 차이입니다.



이번에는 Query String 파싱 예제를 해보겠습니다.


만약 localhost:3000/post/2?body=reactrouter 라는 query string이 들어오면 어떻게 될까요?


이 querystring을 사용하여 어떠한 작업을 하고 싶다면??


props의 location.search 를 사용하시면 됩니다.


이것을 parsing 하기 위해서 이번 포스팅에서는 URLSearchParams 라는것을 사용할것인데요,


사실 이것은 브라우져의 지원율이 좀 낮기때문에 사용하는것에 제약을 두시기 바랍니다.


지금은 공부하는것이므로 사용해보겠습니다.


( query-string 이라는 라이브러리를 다운받아 쓰셔도 됩니다! )


import * as React from 'react';
import { RouteComponentProps } from 'react-router-dom';

const Post = (props: RouteComponentProps<{ postId: string}>) => {
function goNextPost() {
const currPostId = props.match.params.postId;
const nextPostId = +props.match.params.postId + 1 + '';
const { pathname } = props.location;
const nextPath = pathname.replace(currPostId, nextPostId);
props.history.replace(nextPath);
}
return (
<div>
<h3>Post {props.match.params.postId}</h3>
<p>{new URLSearchParams(props.location.search).get('body')}</p>
<button onClick={goNextPost}>Next post</button>
</div>
);
};

export default Post;


return 에 query string을 표시해주는것을 추가하였습니다.


URLSearchParams를 이용하여 props.location.search의 body={ 값 } 을 해석하여 렌더링 할것입니다.


만약 .get('body') 를 빼면 어떻게 나오는지는 한번 해보시기 바랍니다.


자 그럼 실행하여 location:3000/post/2?body=리액트라우터

라고 해보세요.



query string이 제대로 렌더링 되는것을 확인할수 있습니다.


즉 query string을 이용하여 어떠한 작업이 필요하다면 props.loaction.search를 이용하여 query string을 가져와서 사용하면 될것 같습니다.


정리입니다.


Route를 통해 component에는 총 3개의 객체가 넘어오게 됩니다.


1. history

2. location

3. match


- history

- 브라우져의 window.history와 비슷합니다.

- 주소를 임의로 변경하거나 되돌아갈수 있도록 합니다,

- 주소를 변경하더라도 SPA의 특성에 맞게 페이지 전체를 리로드 하지 않고 페이지 일부만 리로드 합니다.


-location

- 브라우져의 window.location와 비슷합니다.

- 현재 페이지에 대한 정보를 가지고 있으며, URL을 쉽게 쪼개서 가지고 있습니다.

- URL의 query정보 또한 가지고 있습니다.


- match

- Route의 path에 정의한 것과 매치된 정보를 담고 있습니다.


이번 포스팅에서는 Route에서 compoenet로 넘어오는 prop에 대해 알아보았습니다.


소스코드 주소입니다.


https://github.com/JaroInside/tistory-react-typescript-study/tree/12.react-router-part2


clone 후 branch checkout 하여 확인 가능합니다.


감사합니다.



참고 슬라이드 - http://slides.com/hyunseob/react-router#/
참고 동영상 - https://www.youtube.com/playlist?list=PLV6pYUAZ-ZoHx0OjUduzaFSZ4_cUqXLm0



블로그 이미지

Jaro

대한민국 , 인천 , 남자 , 기혼 , 개발자 jaro0116@gmail.com , https://github.com/JaroInside https://www.linkedin.com/in/seong-eon-park-16a97b113/

,