[React]React SPA

도시·2022년 6월 7일
0

React

목록 보기
2/11
post-custom-banner

1. SPA란?

SPA란 Single Page Application의 약자로, 서버로부터 완전히 새로운 페이지를 불러오는 것이 아닌 필요한 데이터만 서버에서 전달받아 브라우저에 업데이트하는 방식으로 작동하는 웹 앱플리케이션 or 웹 사이트를 말한다.


📋 SPA 등장 배경

전통적인 웹 사이트에서는 사용자가 웹사이트 내의 다른 페이지로 이동하면, 브라우저가 페이지를 보여주기 위해 HTML 파일로 된 전체 페이지를 불러왔다.

하지만 그 이후, 웹 사이트가 보다 복잡해지고 다양한 형태를 가지게 되면서 사용자와 많은 상호작용이 일어나게 되었고, 전체 페이지를 불러오는 것이 불필요한 트래픽을 발생시켰다.

1990년대 후반부터는, HTML 파일로 된 전체 페이지를 불러오는 것이 아닌 업데이트에 필요한 일부 데이터만 서버에 전달받아 화면에 보여주는 방식이 개발되어 사용되기 시작했다. 2000년대 중반부터 이 방식이 보편화 되면서 이것을 SPA(Single-Page Application) 이라 불렀다.


📋 SPA의 장점

필요한 부분의 데이터만 받아 화면을 업데이트하면 되기 때문에
👉 사용자와의 interaction에 빠르게 반응한다.
👉 서버 과부화 문제가 줄어든다.
👉 더 나은 UX(User Experience)를 제공한다.


📋 SPA의 단점

👉 JavaScript 파일의 크기가 크기 때문에, 첫 화면 로딩 시간이 길어진다.

  • 브라우저는 첫 화면 로딩 시에 HTML 파일을 읽어들인 후 그 안의 script에 있는 JavaScript 파일을 다시 받아오는 과정을 거치는데, SPA는 HTML 파일은 거의 비어있고 JavaScript 파일을 기다리는 시간으로 인해 로딩 시간이 길어지게 된다.

👉 검색 엔진 최적화(SEO)가 좋지 않다.

  • 검색엔진 최적화란 구글이나 네이버 같은 검색엔진이 자료를 수집하기 좋도록 웹 페이지를 구성하는 것을 말한다. SPA는 HTML이 비어있다 보니 검색 엔진이 충분한 자료를 수집하지 못한다.
    -> SPA에서도 검색 엔진 최적화에 대응할 수 있도록 검색 엔진이 발전하고 있어, 단점이 사라지고 있는 추세이다.


2. React Router란?

📋 SPA와 라우팅

SPA는 하나의 페이지를 가지고 있지만, 여러 종류의 화면을 사용한다.
ex) Twittler SPA를 만들 경우, 메인 트윗 모음 페이지, 알림 페이지, 마이 트윗 페이지 등의 화면이 필요

예시와 같이 화면에 따라 '주소'가 달라지고, 주소에 따라 다른 뷰를 보여주는 과정을 라우팅(Routing) 이라 한다.

React 자체에 라우팅 기능이 내장되어 있지 않기 때문에 React SPA에서는 라우팅을 위해 React Router 라는 라이브러리를 사용한다.


📋 React Router 활용

React Router 주요 컴포넌트

  • React Router의 주요 컴포넌트는 크게 3가지로 나눌 수 있다.
    👉 <BrowserRouter>: 라우터 역할
    👉 <Routes> & <Route>: 경로를 매칭
    👉 <Link>: 경로를 변경하는 역할

  • React Router의 컴포넌트들을 사용하기 위해서는 React Router 라이브러리에서 따로 불러와야 한다.
    import는 필요한 모듈을 불러오는 역할로 '비구조화 할당(destructuring assignment)'과 비슷하게 이용함.

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

📋 React Router 설치

npx로 설치하는 방법

$ npx create-react-app test
$ cd test

npm으로 설치하는 방법

$ npm install react-router-dom@^6.3.0

3. 실습

📋 React Twittler SPA

👉 App 루트 컴포넌트(App.js)

import React from 'react';
import './App.css';
import {BrowserRouter, Routes, Route, useNavigate} from "react-router-dom";

import Sidebar from './Sidebar';
import Tweets from './Pages/Tweets';
import MyPage from './Pages/MyPage';
import About from './Pages/About';

const App = () => {
  return (
    <BrowserRouter>
    <div>
      <div className="App">
        <main>
          <Sidebar />
          <section className="features">
            <Routes>
              <Route path="/about" element={<About />}></Route>
              <Route path="/mypage" element={<MyPage />}></Route>
              <Route path="/" element={<Tweets />}></Route>
            </Routes>
          </section>
        </main>
      </div>
    </div>
    </BrowserRouter>
    
  );
};

export default App;

👉Sidebar 메뉴 컴포넌트(Sidebar.js)

import React from 'react';
import { Link } from "react-router-dom";

const Sidebar = () => {
  return (
    <section className="sidebar">
        <Link to="/"><i className="far fa-comment-dots"></i></Link>
        <Link to="/about"><i className="far fa-question-circle"></i></Link>
        <Link to="/mypage"><i className="far fa-user"></i></Link>
    </section>
  );
};

export default Sidebar;

👉Footer 컴포넌트(Footer.js)

import React from 'react';

const Footer = () => {
  return <footer><p>Copyright @ 2022 Code States</p></footer>;
};

export default Footer;

👉Tweets 컴포넌트(Tweets.js)

import React from 'react';
import { dummyTweets } from '../static/dummyData';
import './Tweets.css';

import Footer from '../Footer';

const Tweets = () => {
  return (
    <div>
      <div className="tweetForm__container">
        <div className="tweetForm__wrapper">
          <div className="tweetForm__input">
            <div className="tweetForm__inputWrapper">
              <div className="tweetForm__count" role="status">
                <span className="tweetForm__count__text">
                  {'total: ' + dummyTweets.length}
                </span>
              </div>
            </div>
          </div>
        </div>
      </div>
      <ul className="tweets">
        {dummyTweets.map((tweet) => {
          return (
          <li className="tweet" id={tweet.id} key={tweet.id}>
            <div className="tweet__profile">
              <img src={tweet.picture} />
            </div>
            <div className="tweet__content">
              <div className="tweet__userInfo">
                <span className="tweet__username">{tweet.username}</span>
                <span className="tweet__createdAt">{tweet.createdAt}</span>
              </div>
              <div className="tweet__message">{tweet.content}</div>
            </div>
          </li>
          )
        })}
      </ul>
      <Footer />
    </div>
  );
};

export default Tweets;

👉MyPage 컴포넌트(MyPage.js)

import React from "react";
import { dummyTweets } from "../static/dummyData";
import "./MyPage.css";

import Footer from "../Footer";

const MyPage = () => {
  const filteredTweets = dummyTweets.filter(obj => obj.username === 'kimcoding');

  return (
    <section className="myInfo">
      <div className="myInfo__container">
        <div className="myInfo__wrapper">
          <div className="myInfo__profile">
            <img src={filteredTweets[0].picture} />
          </div>
          <div className="myInfo__detail">
            <p className="myInfo__detailName">
              {filteredTweets[0].username} Profile
            </p>
            <p>28 팔로워 100 팔로잉</p>
          </div>
        </div>
      </div>
      <ul className="tweets__mypage">
        <li className="tweet" id={filteredTweets[0].id}>
          <div className="tweet__profile">
            <img src={filteredTweets[0].picture} />
          </div>
          <div className="tweet__content">
            <div className="tweet__userInfo">
              <span className="tweet__username">{filteredTweets[0].username}</span>
              <span className="tweet__createdAt">{filteredTweets[0].createdAt}</span>
            </div>
            <div className="tweet__message">{filteredTweets[0].content}</div>
          </div>
        </li>
      </ul>
      <Footer />
    </section>
  );
};

export default MyPage;
profile
UI·UX Designer/Frontend Dev
post-custom-banner

0개의 댓글