* 동적 라우트 매칭
- 지난 장에서는 라우트를 3개만 사용했으나 이 이상으로 갯수가 늘어나면 너무 방대해지고 관리하기 힘들기 때문에 동적 라우트 매칭을 사용한다.
import React from 'react';
import { BrowserRouter, Route, Link} from 'react-router-dom'
import GameMatcher from './GameMatcher'
const Games = () => {
return (
<BrowserRouter>
<div>
<Link to="/game/number-baseball">숫자야구</Link>
<Link to="/game/rock-scissors-paper">가위바위보</Link>
<Link to="/game/lotto-generator">로또</Link>
<Link to="/game/index">게임 매쳐</Link>
</div>
<div>
<Route path="/game/:name" component={GameMatcher}/>
</div>
</BrowserRouter>
);
};
export default Games;
- 이 때에는 새로운 컴포넌트를 만들어서 기존의 라우터들을 관리하게 되고, 여기서는 그것들을 관리하는 하나의 라우트만 작성한다. 이 때 :name 부분을 파라미터 또는 params라고 부른다. 이 부분이 바뀌면서 컴포넌트들을 보여주게된다.
- 링크들의 앞에 /games/ 를 붙이고 위와 같이 라우트들을 제거했다. 이제 하나의 주소로 통일된 것이다. 이제 GameMatcher라는 새로운 컴포넌트에서 화면을 구분해주자.
import React, { Component } from 'react';
import NumberBaseball from '../숫자야구/NumberBaseball'
import RSP from '../가위바위보/RSP'
import Lotto from '../로또/Lotto'
class GameMatcher extends Component {
render() {
if (this.props.match.params.name === 'number-baseball') {
return <NumberBaseball />
} else if (this.props.match.params.name === 'rock-scissors-paper') {
return <RSP />
} else if (this.props.match.params.name === 'lotto-generator') {
return <Lotto />
}
return (
<>
<div>
일치하는 게임이 없습니다.
</div>
</>
)
}
}
export default GameMatcher;
- 메인 컴포넌트에서 만들었던 라우트 컴포넌트에서 props로 history, location, match를 넘겨준다.
- history에는 페이지를 넘나든 기록이나 뒤로가기 앞으로가기 등의 기능들이 함수로 저장되어있다. 리액트라우터는 한페이지 속의 눈속임이므로 실제로 페이지가 바뀌지는 않는다. 따라서 브라우저가 기본적으로 제공하는 API를 사용할 수 없다. 그래서 history에 별도로 메서드가 존재한다. 리액트라우터의 historyAPI는 브라우저의 historyAPI를 일부 활용하고 있다.
- match는 실제 라우트에 등록한 주소와 params가 있고, 그 params안에는 임의로 등록했던 주소가 담겨있다. 즉 match는 params에 대한 정보가 주로 담겨있다.
- location은 pathname(주소이름)과 hash나 search등이 담겨있다. 여기서 location은 주소에 대한 정보를 중점적으로 다룬다.
- 어쨌든 우리는 각각의 주소에 대응하는 컴포넌트를 보여주기 위해 분기처리를 해야한다. 이 때 match를 이용했음을 알 수 있다. this.props.match.params.name으로 바뀌는 params 값에 따라 다른 컴포넌트를 return시켰다. 없는 주소를 입력하면 일치하는 게임이 없다는 문구를 출력하도록 하였다.
- 동적라우트매칭을 사용하면 메인컴포넌트의 라우트 부분은 짧게 사용할 수 있으나 별도 컴포넌트가 길어진다는 단점이 있다.
* 쿼리스트링
- 쿼리스트링은 주소로 데이터를 전달할 수 있다.
<BrowserRouter>
<div>
<Link to="/game/number-baseball?page=10&name=haryy&say=hello">숫자야구</Link>
<Link to="/game/rock-scissors-paper">가위바위보</Link>
<Link to="/game/lotto-generator">로또</Link>
<Link to="/game/index">게임 매쳐</Link>
</div>
<div>
<Route path="/game/:name" component={GameMatcher}/>
</div>
</BrowserRouter>
- 숫자 야구 부분의 주소를 보면 데이터를 전달 했음을 알 수 있다.
- ?(물음표)와 함께 key와 value를 줄 수 있고, 데이터가 여러 개 일대에는 &로 구분한다.
- 이 방식으로 전달하면 서버도 알아챌 수 있다.
- 이 데이터는 location의 search부분에 있다.
- props를 받았던 컴포넌트로 다시 돌아가서 이 정보를 받아보자.
class GameMatcher extends Component {
render() {
let urlSearchParams = new URLSearchParams(this.props.location.search.slice(1));
console.log(urlSearchParams.get('name'));
- URLSearchParams는 리액트 라우터의 기능은 아니지만 주소로 받은 데이터를 파싱하여 객체로 만들어주는 역할을 한다.
- 이를 통해 get메서드로 name을 출력시키면 콘솔창에 harry가 출력된다.
- 위 기능은 페이지 번호를 넘겨줄 때와 같이 부가적인 정보를 서버에 줄 때 유용하다.
* switch와 exact
- 메인 컴포넌트에서 라우트를 작성할 때 우리는 종종 원하지 않는 상황과 마주한다. 기존에 라우트에서 다음과 같은 라우트를 추가하면 어떻게 될까.
<div>
<Route path="/game/:name" component={GameMatcher}/>
<Route path="/" component={GameMatcher}/>
</div>
- 우리는 보통 라우트를 여러개 적어두면 하나만 나오기를 원하지만 하나가 동적라우팅이고 다른 하나는 고정된 주소이므로 두가지 모두 나오게 된다.
- 이럴 때에 사용하는 것이 Switch이다. 리액트 라우터 돔에서 import를 해주고 다음과 같이 작성한다.
<div>
<Switch>
<Route path="/game/:name" component={GameMatcher}/>
<Route path="/" component={GameMatcher}/>
</Switch>
</div>
- 이렇게 되면 링크클릭 시 첫번째로 일치하는 것만 뜨게한다.
- 하지만 여기서도 문제가 발생한다. 위의 라우트가 순서가 바뀌면 상위주소가 먼저 검사된다. 리액트라우터는 상위주소도 항상 일치한다고 생각하므로 원하지 않는 컴포넌트가 뜨게될 것이다.
- 상위주소를 다르다고 판단하게 하려면 exact를 사용해야한다. exact를 사용하면 완전히 일치하는 것만 띄운다.
<div>
<Switch>
<Route exact path="/" component={GameMatcher}/>
<Route path="/game/:name" component={GameMatcher}/>
</Switch>
</div>
- 위와 같이 작성하면 비록 상위주소가 먼저 검사되더라도 정확하게 일치하지 않으므로 다음 라우트로 넘어간다.
참고
이 글은 ZeroCho 님의 리액트 무료 강좌를 수강하며 개인적으로 정리하며 쓰는 글입니다.
인프런
유튜브
'Client > React.js' 카테고리의 다른 글
<리액트 기초> 리액트 라우터 (0) | 2021.03.10 |
---|---|
<리액트 기초> Context API (0) | 2021.03.01 |
<리액트 기초> useReducer (0) | 2021.02.26 |
<리액트 기초> useMemo & useCallback (0) | 2021.02.24 |
<리액트 기초> useEffect (0) | 2021.02.22 |