본문 바로가기

오픈소스/노드

[Node] React 정리(4) - SPA react-router-dom 를 사용하여 라우터 만들기 - BrowserRouter, Switch, Route, Link

리액트로 프로젝트를 생성하여 개발하는 과정 중 리액트의 필수 문법 및 기초적인 부분, 심화 과정 등을 정리한 문서입니다. 정리한 부분에는 제가 이해하는 관점에서만 정리를 하였기 때문에 초점은 보여주는 형식이 아닌 제가 필요할 때 사용하려는 목적이 담겨져 있습니다. 이 문서는 어떠한 리액트의 이론을 다루는 것이 아닙니다. 또한 현재 정리하려는 것은 여러분이 필요한 JSX 부분이 아닐 수 있음을 알려드립니다.

 

 본 과정에서는 차례대로 난이도가 증가하는 정리를 하지 않았습니다. 필요한 부분만을 사용하거나 훑어보는 용도로 사용하시기 바랍니다.

 

 먼저 SPA란 무엇인가에 대해 알아보도록 합시다. SPA는 Single Page Application(싱글 페이지 애플리케이션)의 약어입니다. 말 그대로 한 개의 페이지로 이루어진 애플리케이션이라는 의미입니다. 전통적인 웹 페이지는 다음과 같이 여러 페이지로 구성되어 있습니다. 아래는 기존의 웹 페이지 형태입니다.

 

 

기존에는 사용자가 다른 페이지로 이동할 때마다 새로운 html을 받아 오고, 페이지를 로딩할 때마다 서버에서 리소스를 전달받아 해석한 뒤 화면에 보여주었습니다. 이렇게 사용자에게 보이는 화면은 서버 측에서 준비했습니다. 사전에 html 파일을 만들어서 제공하거나, 데이터에 따라 유동적인 html을 생성해 주는 템플릿 엔진을 사용하기도 했었습니다. 요청받는 모든 페이지를 생성하는 것은 성능면에서도 효율면에서도 떨어지는 편이었습니다.

 

 

 

그래서 리액트 같은 라이브러리 혹은 프레임워크를 사용하여 뷰 렌더링을 사용자의 브라우저가 담당하도록 하고, 우선 애플리케이션을 브라우저에 불러와서 실행시킨 후에 사용자와의 인터랙션이 발생하면 필요한 부분만 자바스크립트를 사용하여 업데이트해 줍니다. 만약 새로운 데이터가 필요하다면 서버 API를 호출하여 필요한 데이터만 새로 불러와 애플리케이션에서 사용할 수도 있죠.

 

 리액트에서 SPA를 지원하는 라이브러리 react-router-dom 에 대해 사용법을 알아보도록 하겠습니다.

 

 

# Contents


  • react-router-dom
  • 예제 코드

 

 

# react-router-dom


 리액트의 SPA를 이용하려면 react-router-dom 이라는 라이브러리를 설치해야 합니다. 

 설치 커맨드는 아래와 같습니다.

 

npm install react-router-dom

 

 그러면 react-router-dom 에 지원하는 함수들을 알아보도록 하겠습니다.

 


BrowserRouter

HTML5 history API를 활용하여 UI의 업데이트 처리를 도와주는 함수입니다. 해당 함수는 동적인 페이지를 생성할 때 보편적으로 사용하는 함수로써 라우팅 기능을 제공합니다.

 

Switch

경로의 충돌 현상이 일어나지 않게 라우터의 목록을 관리하는 역할을 합니다.

스위치 내부에 라우터를 작성하게 되면 렌더링 시 현재 URL을 라우터에 정의된 경로와 비교하여 확인하고, 일치하는 첫 번째 라우터를 제공하여 렌더링합니다. 

JavaScript의 Switch 문에서 case 문의 순서가 중요한 것 처럼, 여기서는 라우터의 순서가 중요합니다. 마지막의 라우터 경로를 에러처리하고 싶다면 path=* 로 작성하면 됩니다.

 

Route

요청받은 path에 해당 컴포넌트를 랜더링합니다. exact:true를 지정하게 되면 라우터에게 경로가 정확히 path인 경우에만 일치하도록 지시하게 됩니다.

 

Link

링크를 생성합니다.

 


 

 

# 예제 코드


 간단하게 정적인 페이지를 생성하도록 하겠습니다. 링크를 클릭하게 되면 각각의 페이지로 이동하고, 그 이동된 페이지에서는 무엇을 클릭하였는지 Body 부분에 적는 결과값으로 넣도록 하겠습니다. 아래 완성된 소스코드를 이용하여 파악해보세요.

 

 index.js

 

import react from "react";
import reactDOM from "react-dom";
import htm from "htm";
import { BrowserRouter } from "react-router-dom";
import { App } from "./App.js";

const html = htm.bind(react.createElement);

reactDOM.render(html`<${BrowserRouter}> <${App} /> </${BrowserRouter}>`, document.getElementById("root"));

 

 App.js

 

import react from "react";
import { Switch, Route } from "react-router-dom";
import htm from "htm";
import { MainIndex } from "./component/mainIndex.js";
import { MyList } from "./component/myList.js";

var html = htm.bind(react.createElement);

export class App extends react.Component {
    render() {
        return html`<${Switch}>
        <${Route} path="/" exact=${true} component=${MainIndex} />
        <${Route} path="/list/:listId" component=${MyList} />
    </${Switch}>`;
    }
}

 

 header.js

 

import react from "react";
import htm from "htm";
import { Link } from "react-router-dom";

var html = htm.bind(react.createElement);

export class Header extends react.Component {
    render() {
        return html`<div>
            <h1>Hello World.</h1>
            <${Link} to="/">My Library</${Link}>
        </div>`;
    }
}

 

 mainIndex.js

 

import react from "react";
import { Link } from "react-router-dom";
import htm from "htm";
import { Header } from "./header.js";

var html = htm.bind(react.createElement);
var arr = ["react", "vue", "javascript"];

export class MainIndex extends react.Component {
    render() {
        return html`<div>
            <${Header} />
            ${arr.map(
                (val) => html`<p>
                    <${Link} to="${`list/${val}`}">${val}</${Link}>
                </p>`
            )}
            <p><${Link} to="${`/err`}">Errorpage </${Link}></p>
        </div>`;
    }
}

 

 myList.js

 

import react from "react";
import { Link } from "react-router-dom";
import htm from "htm";
import { Header } from "./header.js";

var html = htm.bind(react.createElement);

export class MyList extends react.Component {
    render() {
        var value = this.props.match.params.listId;
        return html`<div>
            <${Header} />
            선택하신 목록은 : ${value}
        </div>`;
    }
}