React SPA

0

REACT

목록 보기
2/12
post-thumbnail

혹시나 잘못된 개념 전달이 있다면 댓글 부탁드립니다. 저의 성장의 도움이 됩니다

오늘의 Checkpoint

React SPA

Single Page Application
페이지 전체를 새로 로딩하는 기존 방식과는 달리, 한 페이지 내에서 변화가 필요한 일부분의 데이터만 받아와서 렌더링하는 방식
-> 서버로부터 업데이트가 필요한 영역의 JSON 형식 데이터를 받아서 Javascript를 통해 html 요소를 생성/추가하여 리로드
-> 한 페이지에서 화면 변화

cf. MPA(Multi Page Application)
: 페이지 전체를 새로 받아서 렌더링 하는 방식
-> 잦은 트래픽과 속도 저하로 인한 사용자 경험 저하

SPA 장점

  • 빠른 반응 속도
  • 서버 과부하 감소
  • 더 나은 사용자 경험 제공

SPA 단점

  • 첫 화면 로딩 시간이 김
    : html파일은 거의 비어있고 Javascript파일 크기가 커서 처음 받아와야하는 용량이 큼
    spa 방식 html 예시

  • 검색 엔진에 최적화 낮음
    : html 파일 위주로 검색 엔진이 반응하기 때문에 html 대신 Javascript로 정보를 표현하는 SPA는 상대적으로 불리
    cf. 최근에는 검색 엔진이 SPA에도 대응할 수 있도록 개발되고 있으나 검색 노출이 중요한 서비스의 경우 검색 엔진 최적화에 대한 대응책을 따로 대비해야함

cf. SPA 방식 사이트 : 페이스북, gmail, 에어비엔비, 넷플릭스

Wireframe

디자인 작업 전 페이지의 레이아웃과 UI 요소에 대한 윤곽선 / 틀을 잡는 것
-> 디자인 컨셉, 사이트 기능 파악
피그마 와이어프레임

Mockup
최소한의 기능만을 구현해 놓은 모형(데모 시연, 평가용)

컴포넌트 기반 개발은 어떤 기능(component)을 만들고 조합할지부터 구상해야함
-> 와이어 프레임으로 구상


Component 구상 계획

  • 컴포넌트 속의 작은 컴포넌트 구분
    -> 크게 나누고 세부적으로 구분
    : 최종적으로는 데이터에서 어떤 값을 어디에 사용하는지, 클릭할 때의 동작까지 구상
  • 재활용 가능한 컴포넌트 파악
    -> 의존 X, 독립성
    : 동일한 레이아웃이나 모든 페이지에서 노출되야하는 부분등은 함수화하여 재활용

독립적이지만 어플리케이션 내에서 데이터를 유기적으로 주고받을 수 있게 설계해야함



React Router

SPA 방식의 어플리케이션에서 경로에 따라 다른 화면을 보여주는 라이브러리
-> React 설치된 환경에서 사용할 수 있는 라우팅 라이브러리

  • Routing : URL 경로에 따라 다른 뷰를 렌더링
    • <BrowserRouter /> : 라우터 역할
    • <Routes/> , <Route/> : 경로를 매칭
    • <Link/> : 바뀐 경로를 연결
      cf. <Routes /><Routes></Routes> 혼용

코드스테이츠 라우트 그림

React Router 설치하기
터미널에서 create-react-app 로 프로젝트 파일을 설치하고 해당 파일 내부로 이동을 한 후 npm 명령어로 설치 진행

npx create-react-app simpleroute
cd simpleroute
npm install react-router-dom@^<버전>

React Router 설치 공식문서 참조

npm install react-router-dom@^6.3.0 성공

React Router 불러오기
파일 상단에 import 명령 추가

import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'
// 4가지중 필요한 것만 { } 안에 넣어불러오기

cf. 구조분해할당 destructuring assignment syntax을 활용한 표현



React Router 적용하기
페이지를 표시하는 컴포넌트 선언 후 App 컴포넌트에 적용할 선언한 컴포넌트와 <Route /> 컴포넌트를 형식에 맞게 추가

<BrowserRouter /> 컴포넌트
: 현재 위치를 저장하고 브라우저의 내장 history API를 사용하여 새로고침 없이 페이지 이동(주소 변경)을 가능하게 하는 컴포넌트
React Router DOM이 사용되는 부분의 상위 컴포넌트로 위치
-> 다른 라우터 컴포넌트들보다 상위에 위치(모든 태그의 최상위 X)

<Routes /> 컴포넌트
: <Route />의 부모 컴포넌트로 경로가 일치하는 컴포넌트를 렌더링
cf. 파일에 <Routes /> 를 사용하지 않은 경우에는 모든 <Route /> 를 표시

<Route /> 컴포넌트
: 조건문처럼 경로가 path 속성값과 일치하는 경우 element 속성값을 렌더링

<Route path="URL경로" element={렌더링하는컴포넌트} />
{/* path의 속성값을 "*"로 지정하면 지정하지 않은 URL로 접근하면 이어진 element 속성값 컴포넌트로 렌더링*/}

<Link/> 컴포넌트
: <a> 태그처럼 클릭하면 지정된 경로로 이동
-> 페이지 전환 없이 컴포넌트 렌더링
cf. <a> 태그는 이동 후 페이지 전체를 받아와 새로고침되는데 이를 방지하기 위함
-> 컴포넌트 상태 유지

<Link to="URL경로">노출되는 텍스트</Link>
<BrowserRouter>
  <div className="App">
    <nav>
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/abut">Mypage</Link>
        </li>
        <li>
          <Link to="/dashboard">Dashboard</Link>
        </li>
      </ul>
    </nav>
    <Routes>
          <Route path="/" element={<Tweets />}></Route>
          <Route path="/about" element={<About />}></Route>
          <Route path="/mypage" element={<MyPage />}></Route>
    </Routes>
  </div>
</BrowserRouter>
/*---- 공식문서 권장 방식 ----*/
// index.js 파일에서 <App /> 의 부모 태그로 <BrowserRouter /> 적용

import * as React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App.js";

const root = ReactDOM.createRoot(
  document.getElementById("root")
);
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

cf. useNavigate()를 사용할 경우 컴포넌트 내부에서 const navigate = useNavigate(); 로 선언하는데 이때, return값의 상단에 <BrowserRouter /> 가 있어도 영향을 받음
-> 권장 방식처럼 index.js 파일에서 <App />를 감싸는 것 권장



SPA 과제

  • <BrowserRouter /> 컴포넌트는 다른 React Router Dome 컴포넌트보다 상위에만 있으면 됨
    -> 최상위를 의미하는 것은 아님

    const App = () => {
      return (
        <div>
            <BrowserRouter>
              <div className="App">
                <main>
                  <Sidebar />
                  <section className="features">
                    <Routes>
                      <Route path="/" element={<Tweets />}></Route>
                      <Route path="/about" element={<About />}></Route>
                      <Route path="/mypage" element={<MyPage />}></Route>
                    </Routes>
                  </section>
                </main>
              </div>
            </BrowserRouter>
          </div>
    
      );
    };
  • <Routes /> 가 없는경우 오류 발생

  • <Link /> 를 사용할 때 새로고침 없이, 현재 상태를 유지하면서 새로운 화면 렌더링


  • JSX 방식으로 데이터의 모든 요소를 렌더링 할 때는 { } 내부에서 map() 를 사용
    -> key 속성 필수!!
    map() 사용시 key 속성 없을때 오류 발생

    // filter 메소드를 이용하여 username이 kimcoding인 요소만 추출
    // 필터링한 값의 0번째 user의 글만 노출
    const MyPage = () => {
      const filteredTweets = dummyTweets.filter((post)=>{
        return post["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">
            {filteredTweets.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 />
        </section>
      );
    };
  • useNavigate() 로 뒤로가기 기능 구현
    : onClick 속성에 콜백함수로 적용
    -> 전달인자에 따라 1회 뒤로가기(-1 전달), 2회 뒤로가기 (-2 전달), 앞으로 가기 (1 전달) 등 가능

    import { useNavigate } from 'react-router-dom';
    
     const Sidebar = () => {
            const navigete = useNavigate();
       
            return (
              <section className="sidebar">
                /*---- 뒤로가기 아이콘 ----*/
                <div onClick={()=>{navigete(-1)}}>
                  <i className="fas fa-arrow-left"></i>
                </div>
    
                <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>
              );
      };
    	```

참고

import의 파일 경로

./ 는 현재 위치, ../ 는 상위 디렉토리 위치
-> 터미널에서 cd 이동 명령어를 사용할 때의 경로로 적용

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

useNavigate()

이벤트가 발생했을 때, URL 경로를 변경
: 보통 뒤로가기 기능보다 로그인 했을 때 Mypage에 들어갈 수 있고, 아닌 경우 로그인 페이지로 접근하는 경우처럼 직접적으로 어떤 경로로 변경하게 사용하는 경우가 많음

import { useNavigate } from 'react-router-dom';

function MypageForm(){
    let navigate = useNavigate();
    function handleClick(){
        if(/* 로그인한 경우 */){
            navigate('/mypage');
        } else {
            navigate('/login');
        }
    }
	return <button onclick= {handleClick}> Mypage </button>;

JSX 문법에선 조건문 삼항연산자 사용해야하지만

  • 컴포넌트를 정의하는 함수 내부에서 if문 사용 가능
  • return에 사용하는 JSX에서는 if문 대신 삼항연산자 or && 연산자로 조건문 적용 가능
    { 조건 && 실행부 }
    // falsy 표현식을 반환하는 경우도 있음 -> 공식문서 참고
    공식문서 조건부 렌더링


이해도 자가 점검 리스트

Chapter1. React SPA

  • SPA(Single-Page Application) 개념을 이해하고 설명할 수 있다.
  • SPA의 장, 단점에 대해 이해하고 설명할 수 있다.
  • 와이어프레임을 보고 어느 부분을 컴포넌트로 구분할지 스스로 정할 수 있다.

Chapter2. React Router

  • React에서 npm으로 React Router를 설치(npm install react-router-dom@^6)하고 이용할 수 있다.
  • React Router를 이용하여 SPA를 구현할 수 있다.
  • 라우팅 구조를 짤 수 있어야 하고, 이에 필요한 기초 문법들을 사용할 수 있어야 한다.

자기주도적 학습 가이드

이해도 자가 점검 리스트의 결과를 토대로 자기주도적 학습 계획을 수립하고 실천해 보세요.

오늘 학습이 어려웠다면 (0~3개)

  • 개념학습 다시 보기
  • 연습문제 문제 다시 풀어보기
  • 이해되지 않는 개념 아고라스테이츠에 질문하기

오늘 학습이 수월했다면 (4~5개)

  • 오늘 학습한 내용 블로깅하기
  • 아고라스테이츠에 올라온 다른 수강생의 질문에 답변하기

추가적인 학습을 하고 싶다면 (6개)

  • 나만의 컴포넌트 페이지를 제작해 봅시다.
    우리는 개별 컴포넌트를 import 구문으로 불러올 수 있는 것을 배웠습니다. 그리고 React Router로 각 페이지를 연결하는 것도 배웠습니다. 이를 응용하여 Twittler SPA 안에 나만의 메뉴와 나만의 컴포넌트를 제작해서 넣어보세요.
  • 아고라스테이츠에 올라온 다른 수강생의 질문에 답변하기



오늘의 나

느낀점
CSS 정말... 막막하다 기술적인 문제도 그렇지만 디자인 소스 없이 작업하는게 시간이 참 오래 걸리는 것 같다. 어떻게 표현해야 좋을지 생각나는게 없어서 더 오래 걸리는 것 같다. 그렇다고 서치하다가 이것저것 시도해보면 결국 조잡해보여서 되돌리다보면 처음과 별반 다르지 않은 것 같다. 자바스크립트는 어떻게 해야겠다는 흐름이 대충 보이는데 CSS는 흩뿌려져있는 데서 바늘 찾는 느낌이랄까...
오늘 과제는 수월하긴 했다. 하지만 JSX 문법이 익숙치 않은 데다가 map()사용할 때 키를 누락하는 경우, 소소하게는 {} 안에서 작성해야하나 하는 정말 작은 부분까지 조금 버퍼링이 걸리는 것 같다. 오늘 세션에 이런저런 질문을 하다가 들었는데 명확하게 구분짖기 보다 많이 써보고 오류나면 그때 대응하라고 하셨다. 집요하게 파는것도 좋긴 하겠지만 상황에 따라 달리 적용해야지.
그리고 잊지 말아야 할 것. map() 콜백함수에 key 속성 추가하기! 그리고 BrowserRouter 컴포넌트는 Routes등의 상단으로 useNavigate()도 같은 페이지에서 사용한다면 자식컴포넌트로 사용. 그리고 보통 index.js에서 <App />을 감싸서 사용하는것 기억하기

개선점 및 리마인드

익숙하게 사용하다가 깊게 들어가는 것도 한 방법

0개의 댓글