본문 바로가기

Client/React.js

<리액트 기초> 동적 라우트 매칭

 

* 동적 라우트 매칭

 - 지난 장에서는 라우트를 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>
        &nbsp;
        <Link to="/game/rock-scissors-paper">가위바위보</Link>
        &nbsp;
        <Link to="/game/lotto-generator">로또</Link>
        &nbsp;
        <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>
        &nbsp;
        <Link to="/game/rock-scissors-paper">가위바위보</Link>
        &nbsp;
        <Link to="/game/lotto-generator">로또</Link>
        &nbsp;
        <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 님의 리액트 무료 강좌를 수강하며 개인적으로 정리하며 쓰는 글입니다.

 

 

 

 

인프런

 

웹 게임을 만들며 배우는 React - 인프런

웹게임을 통해 리액트를 배워봅니다. Class, Hooks를 모두 익히며, Context API와 React Router, 웹팩, 바벨까지 추가로 배웁니다. 초급 웹 개발 프레임워크 및 라이브러리 React 웹 개발 게임개발 온라인 강

www.inflearn.com

 

유튜브

 

리액트 무료 강좌(웹게임)

 

www.youtube.com

 

 

 

'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