React SPA

HanSungUk·2022년 6월 6일
0

React

목록 보기
2/13
post-thumbnail
post-custom-banner

React SPA

현재 코드스테이츠 강의를 통해 프론트엔드를 학습하고 있습니다.
본 포스트는 해당 강의에 대한 내용 정리를 목적으로 합니다.

학습목표

  • SPA(Single-Page Application) 개념을 이해하고 설명할 수 있다.
  • SPA의 장, 단점에 대해 이해하고 설명할 수 있다.
  • 와이어프레임을 보고 어느 부분을 컴포넌트로 구분할지 스스로 정할 수 있다.
  • React에서 npm으로 React Router를 설치(install react-router-dom@6.3.0)하고 이용할 수 있다.
  • React Router를 이용하여 SPA를 구현할 수 있다.
  • 라우팅 구조를 짤 수 있어야 하고, 이에 필요한 기초 문법들을 사용할 수 있어야 한다.

1. React SPA

  • SPA의 등장 배경과 개념
    전통적인 웹사이트는 페이지 이동시 매번 서버에서 HTML 파일로 된 페이지 전체를 불러와야했습니다.(Multiple Page Application)
    SPA(Single-Page Application)는 Menu와 Footer와 같이 페이지 전환 전후에 중복되는 부분은 새로 불러오지 않습니다. 즉, 업데이트가 필요한 부분만 새로 불러옵니다.

  • 전통적인 웹사이트의 한계와 단점
    웹사이트가 보다 복잡해지고 애플리케이션의 형태를 가지게 되면서, 사용자와 서비스 사이에 더욱 많은 상호작용이 일어나게 되었습니다.
    (*현재는 모호해졌지만 웹사이트는 정적 웹페이지, 웹 애플리케이션은 동적인 기능을 가진 웹페이지를 의미하고 있습니다.)
    하지만 이 때마다 Header나 Navigation Bar 등과 같이 중복되는 요소들을 매번 불러오는 것이 서버와의 불필요한 트래픽을 발생시켰습니다.
    이는 사용자 입장에서 매번 모든 페이지를 불러옴에 따라 더 느린 반응성을 갖게 되었고, 애플리케이션과 같은 사용자 경험을 제공하기 어렵게 만들었습니다.

  • SPA의 등장
    1990년대 후반에 HTML 문서 전체가 아닌, 업데이트에 필요한 데이터만 서버에서 전달받아 이 데이터(JSON 파일)를 Javascript가 동적으로 HTML 요소를 생성해서 화면에 보여주는 방식 이 개발되어 사용되기 시작했습니다.
    2000년대 중반부터 이러한 개발 방식을 이용한 웹 애플리케이션이 보편화되었으며, 이것이 우리가 지금 배우고 있는 싱글 페이지 애플리케이션, 즉 SPA이입니다.
    즉, SPA(Single Page Application)란 서버로부터 완전한 새로운 페이지를 불러오지 않고 페이지 갱신에 필요한 데이터(JSON 파일)만 받아 그 정보를 기준으로 현재의 페이지를 업데이트함으로써 사용자와 소통하는 웹 애플리케이션이나 웹 사이트를 의미합니다.

  • SPA의 장점

    • 전체 페이지가 아니라 필요한 부분의 데이터만 받아서 화면을 업데이트 하면 되기 때문에 사용자와의 Interaction에 빠르게 반응합니다.
    • 서버에서는 요청 받은 데이터만 넘겨주면 되기 때문에 서버 과부하 문제가 현저하게 줄어듭니다.
    • 전체 페이지를 렌더링 할 필요가 없기 때문에 더 나은 유저경험을 제공합니다.
  • SPA의 단점

    • SPA 경우 JavaScript 파일의 크기가 큽니다.
      때문에 이 JavaScript 파일을 기다리는 시간으로 인해 첫 화면 로딩 시간이 길어집니다.
      브라우저는 첫 화면 로딩 시에 HTML 파일을 읽어들인 후 그 안의 script 요소 안에 있는 JavaScript 파일을 다시 받아오는 과정을 거칩니다.

    • 검색 엔진 최적화(SEO)가 좋지 않습니다. 구글이나 네이버 같은 검색 엔진은 HTML 파일에 있는 자료를 분석하는 방식으로 검색 기능을 구동합니다. 하지만 SPA의 경우 HTML 파일은 별다른 자료가 없기 때문에 검색 엔진이 적절히 동작하지 못합니다. 이 때문에 검색 노출이 중요한 웹 애플리케이션은 검색 엔진 최적화에 대한 대응책을 따로 마련해야하고, 더불어 앱 안에서 브라우저의 앞으로 가기 / 뒤고 가기 등의 상태 관리도 해야 하기 때문에 개발의 복잡도가 더욱 늘어납니다.

참고로 검색 엔진의 작동 방식은 검색 로봇이 웹 페이지에 있는 정보를 수집하고 분석해서 그 결과값에 인덱스를 만들어 보관하고 있다가 사용자가 검색어를 입력하면 보관하고 있던 인덱스에서 검색어와 가장 연관성이 높은 웹 페이지들을 순서대로 보여주는 방식으로 작동합니다.
검색 로봇은 자료를 수집할 때에 웹 페이지의 URL은 물론이고 HTML 문서 내의 각종 태그나 링크 등을 분석합니다. SPA는 HTML이 거의 비어있다 보니 검색 로봇이 충분한 자료를 수집하지 못합니다.

Wireframe

Wireframe은 디자인에 들어가기 전 단계로 선(wire)를 이용해 윤곽선(frame)을 잡는 것을 말합니다. 이 작업을 통해 개발자는 디자인 컵셉과 사이트 기능에 대한 이해를 할 수 있습니다. 그리고 목업(mockup)은 데스크톱, 스마트폰의 프레임을 덧씌워 직관적으로 이해하기 쉽게 디자인할 것을 말합니다.

만약 React를 이용해서 유튜브 홈페이지를 만든다면 어떻게 설계해나갈까요?

  • 페이지를 만들기 이전에 컴포넌트를 먼저 만들고 조립합니다.
    • 먼저 화면 상단의 경우, 상단 전체를 아우르는 Header라는 컴포넌트가 있고, 그의 자식으로 Search와 Setting이라는 컴포넌트를 만들기로 했습니다.
      Header 컴포넌트는 애플리케이션 내의 어떤 페이지에 가더라도 늘 상단에 위치하기 때문에 한번만 만들어서 모든 페이지에서 사용할 수 있도록 로직을 설계했습니다.
    • 화면 중앙에는 영상을 담고 있는 ContentsList라는 컴포넌트가 있고 그 안에는 동일한 형태로 화면을 구성하고 있기 때문에 Content라는 컴포넌트를 한 번만 만들어 재사용할 수 있도록 설계했습니다.
    • Content 컴포넌트의 내부로 들어가면 상단에는 썸네일, 중앙에는 아바타와 영상 소개 글, 하단에는 채널 이름과 조회 수, 업로드한 날짜가 기재될 수 있겠고, 우리는 이 안에서 다뤄지는 데이터를 컴포넌트들끼리 보다 유기적으로 주고받을 수 있도록 설계해야 합니다.

2. React Router

SPA는 하나의 페이지를 가지고 있지만 사실 한 종류의 화면만 사용하지 않습니다. 예를 들어 네이버 페이지라고 했을 때, 메인 페이지, 메일 페이지, 쇼핑 페이지 등의 화면이 필요합니다. 또한 이 화면에 따라 "주소"도 달라집니다. 이렇게 다른 주소에 따라 다른 뷰를 보여주는 과정을 "경로에 따라 변경한다"라는 의미로 라우팅(Routing)이라고 합니다.
하지만 React 자체에는 이 기능이 내장돼있지 않기 때문에 React Router라는 라이브러리를 가장 많이 사용합니다.

  • React Router 주요 컴포넌트
    • 라우터의 역할을 하는 BrowserRouter
    • 경로를 매칭(route matchers)해주는 RoutesRoute
    • 경로를 변경(route changers)하는 역할을 하는 Link
    import{BrowserRouter, Routes, Route, Link} from "react-router-dom" 명령어를 통해 React Router 라이브러리를 사용할 수 있습니다.
  • React Router 사용 환경 세팅
// simpleroute 폴더에 React App 설치
npx create-reate-app simpleroute
cd simpleroute

// react-router 라이브러리 설치
npm install react-router-dom@^6.3.0
  • App.js로 react-router 컴포넌트 꺼내오기
import React from 'react';
import {BrowserRouter, Routes, Route, Link} from "react-router-dom";

export default function App(){
return (...)
}
  • Route 준비하기
    페이지를 표시하는 컴포넌트 Home, MyPage, Dashboard를 만들어봅시다.
// App.js 하단에 작성합니다.

// Home 컴포넌트
function Home(){
	return <h1>Home</h1>;
}

// MyPage 컴포넌트
function MyPage(){
	return <h1>MyPage</h1>;
}

// Dashboard 컴포넌트
function Dashboard(){
	return <h1>Dashboard</h1>;
}
  • 메뉴 만들기
    페이지를 표시하는 컴포넌트를 만들었고, 각 컴포넌트로 이동할 메뉴를 제작합니다. 메뉴 제작을 위해 <ul>요소와 <li>요소를 이용합니다.

<BrowserRouter> 컴포넌트는 웹 애플리케이션에서 HTML5의 History API를 사용해 페이지를 새로고침하지 않고도 주소를 변경할 수 있게 해줍니다.

function App () {
  return (
 // <BrowserRouter>가 상위에 작성되어 있어야 React Router의 컴포넌트들을 사용할 수 있습니다.
   <BrowserRouter>
      <div>
        <nav>
          <ul>
            <li>
              Home
            </li>
            <li>
              MyPage
            </li>
            <li>
              Dashboard
            </li>
          </ul>
        </nav>

    {/* 주소 경로와 아까 만든 3개의 컴포넌트를 연결해 줍니다. */}
       {/* Routes 컴포넌트는 Route 컴포넌트들을 감싸고 있어야 합니다. */}
        <Routes>
          {/* 경로는 path로 컴포넌트는 element로 연결해 줍니다. */}
          <Route path="/" element={<Home />} /> 
          <Route path="/mypage" element={<MyPage />} /> 
          <Route path="/dashboard" element={<Dashboard />} />
        </Routes>
      </div>
   </BrowserRouter>
  )
}

export default App;

아래 와 같이 ReactDOM의 렌더 단계인 index.js <BrowserRouter>를 널어서 활용할 수도 있습니다.

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);    
  • Routes, Route
    경로를 매칭해주는 역할을 하는 컴포넌트 입니다.
    • <Routes>컴포넌트는 여러 <Route>컴포넌트를 감싸서 그중 경로가 일치하는 단 하나의 라우터만 렌더링을 시켜주는 역할을 합니다. <Routes>를 사용하지 않으면 매칭되는 모든 요소를 렌더링합니다.
    • <Route>컴포넌트는 path속성을 지정하여 해당 path에서 어떤 컴포넌트를 보여줄지 정합니다. <Link>컴포넌트가 정해주는 URL경로와 일치하는 경우에만 작동합니다.
function App () {
  return (
 // <BrowserRouter>가 상위에 작성되어 있어야 React Router의 컴포넌트들을 사용할 수 있습니다.
   <BrowserRouter>
      <div>
        <nav>
          <ul>
            <li>
              Home
            </li>
            <li>
              MyPage
            </li>
            <li>
              Dashboard
            </li>
          </ul>
        </nav>

    {/* 주소 경로와 아까 만든 3개의 컴포넌트를 연결해 줍니다. */}
       {/* Routes 컴포넌트는 Route 컴포넌트들을 감싸고 있어야 합니다. */}
        <Routes>
          {/* 경로는 path로 컴포넌트는 element로 연결해 줍니다. */}
          <Route path="/" element={<Home />} /> 
          <Route path="/mypage" element={<MyPage />} /> 
          <Route path="/dashboard" element={<Dashboard />} />
        </Routes>
      </div>
   </BrowserRouter>
  )
}

export default App;

만약 사용자가 지정된 주소인 '/', '/mypage', '/dashboard'이외의 주소로 접근하게 되면 의도한 화면이 보이지 않을 수 있습니다. 이럴 때 사용할 수 있는 속성이 path='*'입니다. 지정되지 않은 주소로 접근할 시에는 이 속성이 설정되어 있는 컴포넌트를 보여주게 됩니다.

  • Link
    경로를 연결해주는 역할을 하는 컴포넌트 입니다. 페이지 전환을 통해 페이지를 새로 불러오지 않고 애플리케이션을 그대로 유지하여 HTML5 History API를 이용해 페이지의 주소만 변경해줍니다.

React Router에서 <a>요소가 아닌 <Link>를 사용하는 이유는 <a>요소는 페이지를 전환하는 과정에서 페이지를 불러오기 때문에 다시 처음부터 렌더링을 시킵니다. 즉, 새로고침 현상이 일어나게 됩니다.
하지만 <Link>컴포넌트는 페이지 전환을 방지하는 기능이 내장되어 있기 때문에 SPA를 구현할 수 있습니다.

<Link>to속성을 활용하여 <Route>컴포넌트에 설정해 준 path주소를 연결해줍니다.

function App() {
  return (
    <BrowserRouter>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>{/* Link 컴포넌트를 이용하여 경로를 연결합니다 */}
            </li>
            <li>
              <Link to="/mypage">MyPage</Link>
            </li>
            <li>
              <Link to="/dashboard">Dashboard</Link>
            </li>
          </ul>
        </nav>

         <Routes>
          <Route path="/" element={<Home />} /> 
					{/* 경로는 path로 컴포넌트는 element로 연결해 줍니다. */}
          <Route path="/mypage" element={<MyPage />} /> 
          <Route path="/dashboard" element={<Dashboard />} />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

function Home() {
  return <h1>Home</h1>;
}

function MyPage() {
  return <h1>MyPage</h1>;
}

function Dashboard() {
  return <h1>Dashboard</h1>;
}

export default App;
  • useNavigate를 이용하여 뒤로가기 기능 만들기
import { useNavigate } from "react-router-dom";

navigate(-1) // 뒤로 가기
navigate(1) // 앞으로 가기
post-custom-banner

0개의 댓글