[React] React SPA와 React Router

KIM DA MI·2023년 3월 23일
1

React

목록 보기
2/7
post-thumbnail

이번 시간에는 SPA(Single Page Application)의 등장 배경과 개념, 그리고 장단점에 대해 알아보자.

1. React SPA


🧾 SPA의 등장 배경

  • 전통적인 웹사이트는 사용자가 다른 페이지로 이동할 때마다, 브라우저가 새로운 HTML 파일을 불러와서 페이지 전체를 로딩해야 했다.
    이러한 방식은 중복되는 요소들을 매번 불러오는 등 불필요한 트래픽을 발생시키고, 사용자가 페이지를 이동할 때마다 모든 페이지를 로딩해야 하기 때문에 느린 반응성을 가지게 되어 사용자 경험을 저하시키는 문제가 있었다.

  • 그래서 1990년대 후반에는 필요한 데이터만 서버에서 전달받아 JavaScript가 동적으로 HTML 요소를 생성해서 화면에 보여주는 방식이 개발되었고, 2000년대 중반부터는 이러한 방식을 이용한 웹 애플리케이션이 보편화되면서 SPA라는 개념이 등장하게 되었다.


💡 SPA의 개념

  • React의 SPA는 "Single Page Application"의 약자이다.
  • SPA는 이름 그대로, 하나의 페이지에서 모든 컨텐츠를 제공하는 웹 애플리케이션을 의미한다.
  • SPA는 서버로부터 완전히 새로운 페이지를 불러오는 것이 아니라,
    화면을 업데이트하기 위해 필요한 데이터만 서버에서 전달받아 브라우저에서 해당하는 부분만 업데이트하는 방식으로 작동하는 웹 애플리케이션이나 웹 사이트이다.

👍 SPA의 장점

  • 필요한 부분만 업데이트하여 빠른 반응성 제공
  • 서버 부하 감소 및 더 나은 사용자 경험 제공
  • 대표적인 서비스들이 SPA 방식으로 제작되어 있어 일반적으로 사용자들이 익숙
    ( ex-페이스북, 유튜브, 인스타그램, 넷플릭스 등 )

    예시

    유튜브를 생각해보면, 홈 화면에서 영상 목록을 보는 동안에도 댓글을 달거나 다른 영상으로 이동할 수 있다. 이때 SPA 방식으로 만들어진 유튜브는, 사용자가 댓글을 달거나 다른 영상을 클릭할 때, 필요한 부분만 로드해서 업데이트하게 된다. 그래서 사용자는 화면이 깜빡이거나 새로고침되는 것 없이 부드럽게 이동하고 업데이트된 정보를 확인할 수 있다.


👎 SPA의 단점

  • 초기 로딩 시 JavaScript 파일 다운로드로 인한 로딩 시간 증가

    예시

    게임을 하려고 할 때, 게임을 위한 JavaScript 파일이 너무 크면 게임을 시작하기 전에 시간이 많이 걸리게 된다.

  • 검색 엔진 최적화에 좋지 않아 SEO에 대한 대응책 필요
  • 상태 관리 등 더 많은 개발 복잡도 요구

    예시

    구글에서 무엇인가를 검색했을 때, SPA 방식으로 만들어진 웹 사이트에서는 검색 결과가 뜨지 않거나, 검색어와 관련된 정보를 찾기 어렵게 된다.
    하지만 검색 엔진이 발전하면서, 이러한 단점을 극복하고 있다. 이제는 SPA 방식으로 만들어진 웹 사이트도 검색 엔진에서 잘 검색되는 경우가 많아졌다.


컴포넌트를 나누는 이유는 무엇일까?


  • React는 SPA를 만들기 위해 사용되며, 화면의 일부를 담당하는 React 컴포넌트로 이루어져 있다. 컴포넌트를 나누는 이유는 크게 두 가지로 나눌 수 있다.

1. 코드 재사용성을 높이기 위해

  • 비슷한 기능을 하는 코드를 한 곳에서 관리하면 유지보수와 확장성이 좋아진다.

    예를 들어, 페이지 내부의 반복되는 요소들이 있다면, 그것들을 컴포넌트로 추출하고 필요한 곳에서 재사용하면 된다.


2. 애플리케이션의 성능을 개선하기 위해

  • 모든 컴포넌트를 한 번에 렌더링하면, 성능이 저하될 수 있다.
    이런 경우, 화면의 일부분만 렌더링하거나, 필요한 시점에 로드할 수 있는 컴포넌트로 분할하여 성능을 개선할 수 있다.

    예를 들어, 웹 사이트에 수백 개의 이미지가 포함되어 있다고 가정해보자.
    이러한 이미지를 한 번에 모두 로드하면 웹 페이지가 로드되는 데 매우 오랜 시간이 걸릴 수 있다.
    따라서 이미지를 작은 그룹으로 나누어 각 그룹을 필요할 때 로드하도록 할 수 있다. 이렇게 하면 웹 페이지가 빠르게 로드되며, 사용자가 스크롤링하면서 필요한 이미지만 로드된다.

  • 따라서, React에서 컴포넌트를 나누는 것은 코드 재사용성과 애플리케이션 성능 개선을 위해 중요하다.
    필요한 시점에 로드되는 컴포넌트로 분할하고, 비슷한 기능을 하는 코드를 추출하여 재사용성을 높이면서, 유지보수와 확장성을 개선할 수 있다.



2. React Router


  • React SPA에서는 경로에 따라 다른 화면을 보여줘야 하며, 이를 위해 React Router 라이브러리를 사용한다.
  • React Router는 라우팅(Routing)을 가능하게 해주는 라이브러리로, 경로에 따라 다른 화면을 보여준다.
  • SPA에는 여러 종류의 화면이 필요하며 경로(Path)에 따라 화면이 변경된다.
  • React에서는 이 기능이 내장되어 있지 않기 때문에 React Router 라이브러리를 사용하여 라우팅을 구현한다.

    예를 들어, Twittler와 같은 SPA에서는 메인 트윗 모음 페이지, 알림 페이지, 마이 트윗 페이지 등 다양한 화면이 필요하며, 이러한 화면은 주소에 따라 다르게 보여지게 된다.



React Router 활용


React Router의 주요 컴포넌트에 대해 알아보자. (BrowserRouter, RoutesRoute, Link)

BrowserRouter

  • BrowserRouter는 라우팅을 가능하게 해주는 역할을 한다.

RoutesRoute

  • RoutesRoute는 경로를 매칭해주는 역할을 한다.
  • Link는 경로를 변경하는 역할을 한다.

React Router 사용 환경 세팅


1. 개발 환경 구축하기

  • 터미널을 열고 다음 명령어를 실행하여 simpleroute 디렉토리에 React 프로젝트를 생성한다.
    실행 후 npm start를 통해 실행 결과가 잘 나오는지 확인한다.
    # simpleroute 폴더에 React App 설치
    npx create-react-app@latest simpleroute
    cd simpleroute
    npm start

  • Create React App 프로젝트가 잘 생성되었다면 이제 React Router를 설치할 차례이다.
    아래 명령어를 실행해보자.
    # react-router 라이브러리 설치
    npm install react-router-dom@^6.3.0

  • 라이브러리가 잘 설치되었다면, package.json 파일의 dependencies 항목에 react-router-dom 이라는 라이브러리가 등록된 것을 확인할 수 있다.

  • 이제 App.js 파일로 가서 최상단에 React Router 라이브러리가 제공하는 컴포넌트들을 사용하기 위한 세팅을 진행한다.
    import React from 'react'
    import { BrowserRouter, Routes, Route, Link } from "react-router-dom"; // 이 구문을 넣어주세요

2. 라우트 준비하기

  • 페이지를 표시하는 컴포넌트 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>;
    }

3. 메뉴 만들기

  • 페이지를 표시하는 컴포넌트를 만들었고, 각 컴포넌트로 이동할 메뉴를 제작한다.
    메뉴 제작을 위해 <ul> 요소와 <li> 요소를 이용한다.

    function App () {
      return (
          <div>
            <nav>
              <ul>
                <li>
                  Home
                </li>
                <li>
                  MyPage
                </li>
                <li>
                  Dashboard
                </li>
              </ul>
            </nav>
          </div>)
    }
    
    export default App;

4. 주소에 따라 페이지 뷰 다르게 만들기

  • 이제 위에서 만든 3개의 컴포넌트를 "주소"에 따라 다르게 만든다.
    • Home 페이지의 주소 "/"
    • MyPage 페이지의 주소 "/mypage"
    • Dashboard 페이지의 주소 "/dashboard"
  • App.js 에 라우팅을 하기 위한 React Router의 주요 컴포넌트를 세팅한다.
    이 컴포넌트를 이용해서 우리가 원하는 "주소에 따른 다른 페이지"를 구현할 수 있다.

BrowserRouter

  • <BrowserRouter> 컴포넌트는 웹 애플리케이션에서 HTML5의 History API를 사용해 페이지를 새로고침하지 않고도 주소를 변경할 수 있게 해준다.
    또한 <BrowserRouter> 가 상위에 작성되어 있어야 React Router의 컴포넌트들을 사용할 수 있다.

    function App () {
      return (
        <BrowserRouter>
          <div>
            <nav>
              <ul>
                <li>
                  Home
                </li>
                <li>
                 MyPage
                </li>
                <li>
                  Dashboard
                </li>
              </ul>
            </nav>
          </div>
        </BrowserRouter>)
    }
    
    export default App;

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

    index.js (React Version 18 기준)

    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 경로와 일치하는 경우에만 작동된다.

  • 이제 <Routes> 컴포넌트와 <Route> 컴포넌트들을 작성해보자.

  • <Routes><Route> 로 주소 경로와 아까 만든 3개의 컴포넌트를 연결해 준다.

    • <Route>path 속성을 이용하여 경로를 작성합니다. 경로와 컴포넌트의 이름은 헷갈리지 않게 동일하게 작성한다.
      <Route> 태그 안에 element 속성으로 연결하고자 하는 컴포넌트를 넣어준다.
    function App () {
      return (
       <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=”*” 이다. 지정되지 않은 주소로 접근할 시에는 이 속성이 설정되어 있는 컴포넌트를 보여주게 된다.


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

  • ReactDOM으로 렌더를 시키게 되면 <Link> 컴포넌트는 <a> 요소로 바뀌는 모습을 볼 수 있다.

    React Router에서 <a> 요소가 아닌 <Link>를 사용하는 이유?

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

  • 이어서 <Link> 컴포넌트도 작성해보자.

  • <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;
  • 모두 작성했다면 npm run start 를 통해 실제로 Create React App 프로젝트 환경에서 React Router를 통해 SPA가 구현되었는지 확인해보자.
    아래와 같이 작동한다면 코드가 올바르게 작성된 것이다.

0개의 댓글