앞서 배운 React webgame은 순수 React를 가지고 프로그래밍 방법을 배워보는데 집중했다. 오늘은 이러한 컴포넌트들이 웹에서 어떻게 동작하는지에 대해 간단히 배워본다.

9-1. React Router 도입하기

먼저 프로젝트에 react-router, react-router-dom 패키지 설치하자. react-router는 웹 뿐만 아니라 앱 환경에서도 사용할 수 있다. 앱 환경에서는 react-router-dom → react-router-app을 설치해주면 된다.

$ npm i react-router react-router-dom

실제로 react-router-dom만 사용하며 그 뼈대인 react-routerreact-router-dom에서 사용한다.

react-router-dom이 설치되었다면, 실제 Router를 설정해보자.

import React from "react";
import { BrowserRouter } from "react-router-dom";
import Lotto from "./src/lotto/Lotto";
import RSP from "./src/rock-paper-scissors/RSP";
import NumberBaseball from "./src/number-baseball/NumberBaseball";

const Games = () => {
  return (
    <BrowserRouter>
      <div>
        <Route path="/number-baseball" component={NumberBaseball} />
        <Route path="/rock-scissors-paper" component={RSP} />
        <Route path="/lotto-generator" component={Lotto} />
      </div>
    </BrowserRouter>
  );
};

export default Games;

위와 같이 각 컴포넌트를 BrowserRouter tag로 감싸주어야 한다. 혹은 위와 같은 방법이 싫다면 ReactDom.render 메서드에 넣어줘도 된다.

// client.jsx

ReactDom.render(<BrowserRouter><App /></BrowserRouter>, document.querySelector('#root'));

9-2. Link와 BrowserRouter

React는 실제 여러 페이지인 것처럼 보이는 하나의 페이지이다. 따라서 react-router-dom 에서 페이지 간의 이동은 a 태그를 사용하는 것이 아닌 react-router-dom에서 제공하는 Link 메서드를 사용한다.

import React from "react";
import { BrowserRouter, HashRouter, Route, Link } from "react-router-dom";
import Lotto from "./src/lotto/Lotto";
import RSP from "./src/rock-paper-scissors/RSP";
import NumberBaseball from "./src/number-baseball/NumberBaseball";

const Games = () => {
  return (
    <BrowserRouter>
      <Link to="/number-baseball">숫자야구</Link>&nbsp;
      <Link to="/rock-scissors-paper">가위바위보</Link>&nbsp;
      <Link to="/lotto-generator">로또추첨기</Link>&nbsp;

      <div>
        <Route path="/number-baseball" component={NumberBaseball} />
        <Route path="/rock-scissors-paper" component={RSP} />
        <Route path="/lotto-generator" component={Lotto} />
      </div>
    </BrowserRouter>
  );
};

export default Games;

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f7811459-2fbf-4f08-842a-fefab18f96a4/_2021-02-07__9.59.08.png

만약 위 설정을 dev로 실행한 뒤 실제 페이지 주소에 path를 넣어치면 좌측과 같은 에러 메시지가 나온다. 왜그럴까? 그 이유는 서버에서는 저 페이지에 대한 정보를 알 수 없기 때문이다.

각 페이지 라우팅에 대한 정보는 오직 client.jsx만이 각 페이지에 대한 정보를 알고 있으므로 위처럼 바로 주소로 유입시 에러가 발생한다. 이러한 설정을 서버에서 맞춰줘야하는데, 그렇게 하기 전 dev환경에서 해당 에러를 보고싶지 않다면 webpack.config 설정 내 devServer에서 historyApiFallback 옵션을 활성화 해주면 개선된다.

9-3. HashRouter, params, withRouter

BrowserRouter와 비슷한 기능으로 HashRouter가 있다. 이번에는 HashRouter로 라우팅 구현을 해보자

const Games = () => {
  return (
    <HashRouter>
			{/* Link, Router... */}
    </HashRouter>
  );
};

export default Games;

위처럼 설정 후 dev를 실행시키면 path에 #이 붙어있다. http://localhost:8080/#/number-baseball 해시라우터를 붙이면 위에서 설명한 서버에서 페이지를 알 수 없다는 오류를 방지할 수 있다.
서버가 해시(#) 뒷 부분에 대해 인식하지 못하기 때문이다. (서버는 모르지만 Client는 안다.)

이러한 특징은 검색엔진, SEO들의 정보수집 동작 시에 문제가 된다.
보통 검색엔진이나 SEO는 데이터를 브라우저에 물어보지 않고, 서버에 물어보기 때문이다.
만약 해시(#)가 있는 상태로 검색엔진 등이 정보를 Request하면 서버는 데이터를 모르기 때문에 정보를 주지못하고 이는 데이터 노출에 영향을 주게 된다.

위와 같은 이유로 실무에서 HashRouter를 잘 쓰지 않는 편이며. (물론 브라우저라우터를 사용해도 SEO를 위해 따로 셋팅이 필요하긴 하다) 보통 주소값이 중요하지않고, 데이터 수집의 필요성이 없는 페이지의 경우 HashRouter를 많이 쓴다.