본문 바로가기
  • soldonii's devlog
Javascript 공부/React

리액트 라우터(React Router)로 라우팅하기

by soldonii 2019. 12. 14.

*Udemy의 "Complete React Developer in 2020" 강의에서 학습한 내용을 정리한 포스팅입니다.

*자바스크립트와 리액트를 배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글로 말씀해주시면 수정하겠습니다. 감사합니다. :)


1. 리액트에서 라우팅하기

리액트로 구현하는 웹페이지는 대부분 Single Page Application, 즉 HTML 파일은 하나만 가지고 있고, 나머지는 자바스크립트로 화면을 통제하여 서버와의 요청/응답 주고받기를 줄여 웹페이지의 로딩 속도를 줄이는 방식을 취하고 있다. 속도 측면에서는 SPA가 장점이 뚜렷하지만, 페이지 간 이동 시 주소의 문제가 발생한다. 

 

예를 들면, 원래는 페이지에 따라서 url link가 달라지게 된다. www.soldonii.com/shop/hats 이런식으로 이동하는 페이지마다 주소가 달라지게 된다. 그런데 SPA는 구조 상 단일 페이지이기 때문에 보여지는 페이지 모습은 달라져도 주소는 달라지지 않는 문제가 발생한다. 이러한 문제를 해결해주기 위해서 등장한 라이브러리가 React Router 라이브러리이다. 

 

# 설치 및 사용법

terminal에서 작업 중인 리액트 프로젝트 폴더로 이동한 후, yarn add react-router-dom으로 설치한다. 이후 프로젝트에 적용하기를 원하면 index.js에서 아래처럼 import하면 된다. 그리고 ReactDOM.render에서 #root를 대체할, 베이스가 되는 App 컴포넌트를 아래처럼 <BrowserRouter>로 감싸주어야 한다. 그렇게 함으로써 react-router-dom 라이브러리가 가지고 있는 모든 기능을 App 컴포넌트가 사용할 수 있게된다.

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom'; // 이렇게 import한다.

import './index.css';
import App from './App';

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

 

2. Route 컴포넌트 사용하기

react-router-dom 라이브러리에는 무수히 많은 컴포넌트가 존재한다. 그 중 대표적인 <Route> 컴포넌트를 알아보자.

// App.js
import React from 'react';
import { Route } from 'react-router-dom';

import HomePage from './pages/homepages/homepage.component';
import './App.css';

const HatsPage = () => (
  <div>
    <h1>HATS PAGE</h1>
  </div>
)	

function App() {
  return (
    <div>
      <Route exact path="/" component={HomePage}/>
      <Route path="/hats" component={HatsPage}/>
    </div>
  );
}

export default App;

위에서 리턴되는 부분을 보면 기존처럼 구현한 컴포넌트를 div에 담는 대신 <Route> 컴포넌트를 div에 담고, rendering이 필요한 컴포넌트를 <Route> 컴포넌트의 프로퍼티로 전달하고 있다.

 

# <Route> 컴포넌트의 주요 프로퍼티 - component, path, exact

1. component는 <Route>가 rendering해야 하는 대상이 되는 컴포넌트를 의미한다.

2. path는 rendering할 대상이 되는 컴포넌트의 주소를 의미한다. 위의 경우 localhost:3000/ 주소는 HomePage 컴포넌트가 렌더링되고, localhost:3000/hats는 HatsPage 컴포넌트가 렌더링된다.

3. exact는 값으로 true, false를 줄 수 있다. 만약 true일 경우 exact={true} 대신 축약해서 exact만 작성하면 된다.

 

function App() {
  return (
    <div>
      <Route path="/" component={HomePage}/>
      <Route path="/hats" component={HatsPage}/>
    </div>
  );
}

만약 위 코드처럼 <Route> 컴포넌트에 exact를 뺄 경우 어떻게 될까? 위 코드에서 localhost:3000/hats 로 접속하면 HomePage 컴포넌트와 HatsPage 컴포넌트가 모두 렌더링된다. 왜냐하면 exact가 없을 경우 localhost:3000/hats 라는 주소 내에 HomePage 컴포넌트가 렌더링되어야 하는 주소인 localhost:3000/ 주소가 포함되어 있기 때문이다. 따라서 localhost:3000/hats 이 주소는 HomePage와 HatsPage 컴포넌트 둘 모두 렌더링 되는 것이다.

 

이를 해결하기 위해서 exact 프로퍼티가 필요한 것이다.

function App() {
  return (
    <div>
      <Route exact path="/" component={HomePage}/>
      <Route path="/hats" component={HatsPage}/>
    </div>
  );
}

이렇게 HomePage 컴포넌트의 경우 프로퍼티로 exact를 작성해주면, 주소가 정확히 localhost:3000/ 일 때에만 HomePage 컴포넌트가 렌더링된다. localhost:3000/hats 주소는 비록 localhost:3000/을 포함하고 있지만, 정확히 localhost:3000/ 이 주소일 때에만 HomePage 컴포넌트가 렌더링되도록 했으므로 HomePage 컴포넌트는 렌더링되지 않고 오직 HatsPage 컴포넌트만 렌더링된다.

 

# Switch 컴포넌트

import React from 'react';
import { Route, Switch } from 'react-router-dom'; // Switch도 렌더링

import HomePage from './pages/homepages/homepage.component';
import './App.css';

const HatsPage = () => (
  <div>
    <h1>HATS PAGE</h1>
  </div>
)

function App() {
  return (
    <div>
      <Switch>
        <Route path="/" component={HomePage}/>
        <Route path="/hats" component={HatsPage}/>
      </Switch>
    </div>
  );
}

export default App;

exact를 주지 않았을 때, 앞선 <Route> 컴포넌트에서는 localhost:3000/hats 라는 주소의 경우 path="/"도 일치하고, path="/hats"도 일치했으므로 HomePage 컴포넌트와 HatsPage 컴포넌트 모두를 렌더링했다. 그런데 이를 <Switch> 컴포넌트 내부에 종속시키면 <Switch> 컴포넌트 내부에 있는 <Route> 컴포넌트들 중 위에서부터 url과 일치하는 것 하나만을 렌더링한다. 

 

따라서 위 코드를 기반으로 만약 localhost:3000/hats 라는 주소에 접속할 경우에, 기존에는 HomePage와 HatsPage가 모두 렌더링됐다면, Switch 안에 들어가는 순간 HomePage 컴포넌트만 렌더링된다. 위에서부터 path와 일치하는 것을 찾는데, HomePage 컴포넌트는 localhost:3000/hats 주소에서 /가 포함되어 있으므로 렌더링이 되기 때문이고, 하나가 렌더링되면 나머지는 렌더링되지 않기 때문이다.

댓글