프론트엔드/실전 리액트 프로그래밍

[스터디 with 실전 리액트 프로그래밍] 4편 - 단일 페이지 어플리케이션

Junheehee 2022. 8. 4. 17:50

실전 리액트 프로그래밍

 

리액트로 만든 어플리케이션의 페이지 전환은 보통 단일 페이지 어플리케이션(single page application, SPA) 방식으로 개발한다.

전통적인 방식은 페이지 전환마다 서버에 html 파일을 요청을 하는 반면에,

단일 페이지 어플리케이션 방식은 처음에만 서버에 데이터를 요청하고 이후 라우팅은 클라이언트에서 처리한다.

이렇게 단일 페이지 어플리케이션으로 개발하면 페이지 전환 시 화면 깜빡임이 없어서 좋은 유저 경험을 제공한다.

 

 

두가지 방법으로 단일 페이지 어플리케이션을 개발해보자.

먼저 브라우저 히스토리 API를 이용해보자.

 

 

브라우저 히스토리 API

 

History - Web API | MDN

History 인터페이스는 브라우저의 세션 기록, 즉 현재 페이지를 불러온 탭 또는 프레임의 방문 기록을 조작할 수 있는 방법을 제공합니다.

developer.mozilla.org

브라우저 히스토리 API를 이용하면 자바스크립트로 브라우저에 페이지 전환 요청을 보낼 수 있다.

히스토리 API에는 pushState, replaceState 등의 함수와 popstate 등의 이벤트가 있다.

브라우저 히스토리에서 state는 stack 구조로 저장되기 때문에 우리는 새로운 페이지를 쌓을 수도 있고(push) 뒤로가기 버튼으로 전 페이지로 전환할 수도 있다(pop).

 

히스토리 API를 이용해서 간단한 단일 페이지 어플리케이션을 만들자.

import React, { useEffect } from "react";

export default function BrowserHistoryAPI() {
  useEffect(() => {
    window.onpopstate = function (e) {
      console.log(`location: ${document.location}, state: ${e.state}`)
    }
  }, [])

  return (
    <div>
      <button onClick={() => window.history.pushState('v1', '', '/page1')}>
        page1
      </button>
      <button onClick={() => window.history.pushState('v2', '', '/page2')}>
        page2
      </button>
    </div>
  )
}

 

 

버튼은 누르면 페이지는 전환된다.

이 때 서버에 데이터를 요청하지 않기 때문에 화면이 깜빡이지 않는다.

버튼 클릭

 

뒤로가기 버튼을 눌러보자.

뒤로가기 버튼 클릭

useEffect 안에 popstate 이벤트 리스터를 달아놨기 때문에 페이지 정보가 콘솔창에 출력되었다.

page 버튼을 클릭했을 때 페이지 state가 히스토리 stack에 쌓였고, 뒤로가기 버튼을 클릭하니 하나씩 pop 되었다.

 

 

react-router-dom

react-router-dom을 이용하면 브라우저 히스토리 API와 달리 라우팅을 직접 처리하지 않고 단일 페이지 어플리케이션을 개발할 수 있다.

우리가 직접 사용하진 않지만, react-router-dom 내부에선 브라우저 히스토리를 이용하니 원리는 같다.

 

react-router-dom 패키지를 설치 한 뒤, 컴포넌트를 만들어보자.

 

import React from "react";
import { BrowserRouter, Route, Link, Routes } from "react-router-dom";
import Rooms from "./Rooms";

export default function ReactRouterDom() {
  return (
    <BrowserRouter>
      <div style={{ padding: 20, border: '5px solid gray' }}>
        <Link to="/">홈</Link>
        <br />
        <Link to="/photo">사진</Link>
        <br />
        <Link to="/rooms">방 소개</Link>
        <br />
        <Routes>
          <Route exact path="/" element={<Home />} />
          <Route exact path="/photo" element={<Photo />} />
          <Route exact path="/rooms/*" element={<Rooms />} />
        </Routes>
      </div>
    </BrowserRouter>
  )
};

function Home() {
  return <h2>홈페이지입니당!</h2>
}

function Photo() {
  return <h2> 사진입니당!</h2>
}

 

react-router-dom을 사용하기 위해선 BrowserRouter 컴포넌트로 전체를 감싸야 한다.

Link 컴포넌트를 통해 페이지 전환이 이루어지고, 현재 주소가 Route 컴포넌트의 path 속성과 같으면 element 속성의 컴포넌트가 렌더링 된다.

 

아래는 위에서 작성한 ReactRouterDom 컴포넌트에서 불러오는 Rooms 컴포넌트다.

import React from "react";
import { BrowserRouter, Route, Link, Routes, useMatch } from "react-router-dom";

export default function Rooms() {
  return (
    <div>
      <h2>방을 소개하는 페이지입니당!</h2>
      <Link to="blue">파란 방</Link>
      <br />
      <Link to="red">빨간 방</Link>
      <br />
      <Link to="green">초록 방</Link>
      <Routes>
        <Route exact path="/" element={<h3>방을 선택하시오</h3>} />
        <Route path=":roomColor" element={<Room />} />
      </Routes>
    </div>
  )
}

function Room() {
  const match = useMatch("/rooms/:roomColor")
  return <h2>{`${match.params.roomColor} 방을 선택했습니다`}</h2>
}

이런식으로 라우팅을 중첩해서 작성할 수 있다.

그리고 react-router-dom의 useMatch를 이용해 파라미터를 사용할 수 도 있다.

 

react-router-dom을 사용한 단일 페이지 어플리케이션

잘 작동하는 것을 확인할 수 있다.

 

 

위의 코드는 간단한 예시여서, 편의상 하나의 자바스크립트 파일안에 여러 컴포넌트를 정의하였다.

하지만 실제로 개발할 때는 하나의 파일에는 하나의 컴포넌트만 정의하는 것이 좋다.

 

 

코드

 

GitHub - junhee-won/react-study: with 실전 리액트 프로그래밍

with 실전 리액트 프로그래밍. Contribute to junhee-won/react-study development by creating an account on GitHub.

github.com