[14주차 Day3] 스프린트 3: React(TypeScript) 기반의 동적 UI 개발

반 히·2024년 5월 30일

데브코스

목록 보기
37/58
post-thumbnail

📚 Part 1 프로젝트 소개

  • 환경 설정 : 리액트 특히 SPA의 생성과 환경 설정
  • 타입과 모델 : 타입을 정의하고 해당 타입으로 모델을 정의, 작성
  • 데이터 흐름 : API 요청부터 화면의 렌더까지 그 데이터의 흐름을 제어
  • 상태 관리 : 컴포넌트의 상태 관리, context API나 외부 라이브러리를 이용한 전역 상태 관리
  • UI 패턴 : modal, 탭, 드롭 다운, 무한 스크롤, 슬라이드 등을 라이브러리 없이 직접 만들어보면서 다양한 UI 패턴 등을 실습해볼 것임.
  • 모바일 대응 : 반응형 웹 도입


📚 Part 2 기본 구조 이해


📁 React 프로젝트 생성 : CRA vs. Vite

📌 CRA

webpack
node.js
express server
source build
process.env.KEY
HMR

  • 초기 설정과 구성을 자동화해서 개발자가 조금 더 빠르게 react 앱을 생성할 수 있도록 도와줌
  • Webpack과 babel을 사용함 → 이를 통해서 개발 서버를 실행해주고, HMR(Hot module Reloading) 적용
  • HMR : 개발 시에 개발 코드를 변경하면 화면에 바로 적용되는 기술
  • Webpack을 통해서 빌드 시에 코드를 컴파일 해주고 압축하는 역할도 해줌
    • 우리는 이번 프로젝트에서 타입스크립트를 사용할 것인데, 타입스크립트도 브라우저에서 직접 구동은 되지 않음.
    • 따라서 이를 브라우저에 맞는 자바스크립트로 컴파일해주고 이 과정에서 압축하고 번들링하는 과정도 해줌
  • 가장 대중적으로 많이 쓰이며, Node.js 사용
  • process.env.KEY : 환경설정, 환경 변수를 사용하는 방법

📌 Vite

ESBuild
Golang
koa server
module build
import.meta.env.KEY
HMR

  • ESBuild 사용
  • webpack 대신 rollup으로 빌드하게 됨
    • webpack에 비해서 속도 크게 개선
    • 특히 개발 모드 HMR에서 빠른 속도를 자랑함
  • golang 사용
  • import.meta.env.KEY : 환경 변수를 다룰 때도 차이가 있음

CRA는 HMR을 할 때 소스 전체를 빌드한다고 하면 Vite는 모듈 단위로 빌드하여 브라우저를 제공하기 때문에 이러한 속도차이가 남

📌 CRA 설치

npx create-react-app book-store-c --template typescript

# 설치 후 아래 명령 사용 시 개발 서버 실행됨 
cd book-store-c
npm run start 

위 명령어를 통해 프로젝트를 위한 기본 코드를 받아오고 node module도 설치함
이 과정에서 우리가 사용할 react와 react-dom, react-scripts 같은 프로젝트에서 사용하는 도구들을 같이 설치하게 됨

📌 Vite를 이용한 프로젝트 설치

npm create vite@latest book-store-v -- --template react-ts

cd book-store-v
npm i

npm run dev 
# 개발 서버 실행 


📁 프로젝트 구조

📌 프로젝트 폴더(디렉토리) 구조

  1. pages - 라우트에 대응하는 페이지 컴포넌트 (컨테이너)
    ▪️ 기본적으로 리액트 컴포넌트가 위치됨.
    ▪️ 라우트(화면 상의 주소)에 대응하는 페이지 컴포넌트를 위치시킬 것임
  2. components - 공통 컴포넌트, 각 페이지에서 사용되는 컴포넌트
    ▪️ 공통으로 쓰이는 컴포넌트들이 위치될 것임
    ▪️ 각 페이지에서 사용되는 컴포넌트들도 위치될 것임
  3. utils - 유틸리티
    ▪️ 앱을 사용하면서 쓰게 될 여러 가지 함수 형태의 유틸리티들을 정의해서 사용할 것임
  4. hooks - 리액트 훅
    ▪️ 리액트에서 자주 쓰이는 훅들을 모아서 관리
  5. model - 모델 (타입)
    ▪️ 서비스에서 다룰 데이터 형태를 정의한 모델(타입)
    ▪️ 인터페이스로 작성
  6. api - api 연동을 위한 fetcher 등
    ▪️ API 연동을 위해 fetch라고 하는 함수인 fetcher를 위치시킬 폴더

필요에 따라 수정 또는 추가될 수 있음.



📁 CLI

📌 React CLI

// 생략
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
//생략
  • start : npm run start 명령으로 개발 서버를 실행함

  • build : npm run build 명령을 실행하면 build라는 폴더가 생성됨

    • index.html : public 폴더 안에 있는 index.html 파일이 압축되고 필요없는 부분들이 제거된 파일이 제공됨. 이 파일 안에 만들 react application이 라우트 됨
    • static : 라우트되는 함수 이하의 코드들이 저장됨
      • js : 타입스크립트로 작성된 app을 자바스크립트로 컴파일하고 bundling해서 만들어진 파일들
    • build 이하의 static 폴더와 다른 index를 포함한 파일들을 static hosting을 이용하는 서버에 올리면 react SPA를 바로 실행할 수 있음 - SPA의 가장 큰 장점 (간단하게 서빙할 수 있다)
  • test : npm run test 명령을 실행하면 app 안에 작성한 테스트 등의 파일을 구동시켜서 test 파일을 실행해줌

  • eject : 기존에 웹페이지를 만들어놓은 설정들을 탈출한다는 뜻

    • 별도의 설정이 필요하거나 eject를 꼭 수행해야만 사용할 수 있는 플러그나 라이브러리를 쓸 때만 사용함

📌 tsc

    "typecheck": "tsc --noEmit --skipLibCheck"

우리는 현재 타입스크립트를 이용한 리액트를 쓰고 있다. 따라서 수시로 타입체크가 필요하다. script에 위 코드를 추가해준다

  • 타입스크립트 컴파일 명령어. 즉, 컴파일을 위한 명령어임
  • 컴파일 중에 타입 오류를 발견할 수 있고, 발견된 것을 사용자(개발자)에게 알려줌
  • 이러한 기능을 이용하여 타입 명령어로 많이 사용함
  • `--noEmit``
    • 자바스크립트로 컴파일 해서 출력하는 부분을 비활성화 하겠다는 의미
    • 타입체크로만 사용하기 때문에 js로 변환하는 과정을 생략하겠다는 옵션
  • --skipLibCheck
    • 작성하고 있는 외부 라이브러리 타입체크를 생략하겠다는 의미
    • 만약 skip하지 않는다면 외부 라이브러리가 많아졌을 때 모두 타입체크를 하므로 시간이 많이 걸리게 됨

📌 tsconfig

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}
  • 타입스크립트가 브라우저에서는 구동이 되지 않기 때문에 자바스크립트로 컴파일하는 과정을 거치고, 이때의 옵션
  • "target": "es5"
    • es5 js 코드로 컴파일하겠다는 뜻
    • 다른 항목이 들어갈 수도 있음
  • Lib
    • 컴파일러가 참조할 라이브러리


📚 Part 3 레이아웃 및 상태 관리


📁 레이아웃 구성

📌 레이아웃은 왜 필요할까

  1. 프로젝트의 기본적인 화면 구조를 잡는다.
    ▪️ Single Page App은 주로 컴포넌트의 조립(조합)으로 이루어짐
    ▪️ 따라서 레이아웃을 이용하여 화면 구조를 잡을 수 있음
  2. 반복적으로 들어가야 하는 헤더, 푸터 등을 매 화면마다 제공한다.
    ▪️ 반복적으로 들어가야 하는 컴포넌트들을 매 화면마다 import하는 것은 중복이 발생함
    ▪️ 따라서 매화면마다 제공하는 역할
  3. 상황과 필요에 따라 레이아웃이 변경될 수 있도록 대비한다.

사용자에게 일관적인 UI를 제공하기 위해서 header와 footer 같은 통일된 UI를 제공하는 것이 일반적인 레이아웃의 역할임. 그러나 많은 수의 웹 프로젝트들은 유동적인 레이아웃을 가지고 있음. 따라서 레이아웃 컴포넌트가 필요함. 이러한 레이아웃을 제공하는 전략은 두 가지가 있는데, 첫 번째는 화면마다 헤더와 푸터 등 공통된 컴포넌트들을 넣어주는 방법이다. 두 번째가 레이아웃을 만드는 방법이다.

import Footer from "../common/Footer";
import Header from "../common/Header";

interface LayoutProps {
    children: React.ReactNode;
}

function Layout({children}: LayoutProps) {
    return (
        <>
            <Header />
            <main>{children}</main>
            <Footer />
        </>
    )
}

export default Layout;

여기서 ReactNode라는 타입은 react로 만든 모든 컴포넌트들이 배치될 수 있다고 선언하는 것임.



📁 글로벌 스타일과 스타일드 컴포넌트

📌 global style

  1. global = 프로젝트 전체에 적용 = 프로젝트에 일관된 스타일링 적용
  2. "user agent stylesheet"로 표시되는 브라우저의 기본 스타일이 차이를 만든다.
  3. 브라우저 간의 스타일 차이를 극복하기 위해 사용

🍀 css의 global style 종류

  1. 에릭마이어의 reset css
    ▪️ element의 모든 스타일을 0이나 100%로 초기화하여 reset css라고 불림
  2. normalize.css
    ▪️ 각 element의 고유한 속성을 유지하면서 기기 간, 브라우저 간 차이를 줄이는 것을 목적으로 함
  3. sanitize.css
    ▪️ normalize가 발전(진보)된 버전
    ▪️ 브라우저와 기기 간의 차이를 줄이는 데 집중함
    ▪️ 이번 프로젝트에서 사용할 방식
npm install sanitize.css --save

save로 패키지에도 저장함

📌 styled component

최근 가장 많이 사용되는 CSS in JS. 웹 개발을 하면서 CSS로 해결할 수 없는 몇 가지 문제가 있는데, 이를 위함

🔗 css-in-js는 왜 필요할까

1️⃣

h1 { 
	font-size: 30px;
}
/* 모든 h1 엘리먼트에 적용됨 */

.box h1 {
	font-size: 30px;
}
<div class="box">
  <h1>Box Title</h1>
</div>
/* .box 하위에 있는 h1에만 적용됨 */

2️⃣

.wrapper h1 {
	font-size: 50px;
}
<div class="wrapper">
  <h1>Wraaper Title</h1>
  <div class="box">
    <h1>Box Title</h1>
  </div>
</div>
/* 여기서 "Box Title"은 어떻게 렌더링 될까요? */

3️⃣

<div className="toggle ${isActive ? 'active' : ''}">
  보여질 내용
</div>
/* 전달해야 할 상태가 여러개라면? */
.toggle {
	display: none;
}
.toggle.active {
	display: block;
}

4️⃣

<link rel="stylesheet" href="리셋.css" />
<link rel="stylesheet" href="라이브러리1.css" />
<link rel="stylesheet" href="라이브러리2.css" />
<link rel="stylesheet" href="우리프로젝트코드.css" />
/* 어떤 것이 우선일까? */

이렇듯 CSS만으로는 스타일의 상태를 적용하기가 어렵고, 의도하지 않은 결과들이 나올 수 있음
이러한 css의 이슈들을 해결하기 위해 CSS in JS를 사용함

🔗 css-in-js가 필요한 이유 정리

  1. 전역 충돌
    ▪️ 기존 css의 전역 충돌을 막기 위해서
  2. 의존성 관리 어려움
    ▪️ style이 기본적으로 형성되어 있기 때문에 의존성 관리가 어려움
    ▪️ 가독성이 떨어지는 코드들을 작성할 수 밖에 없어짐
  3. 불필요한 코드, 오버라이딩
    ▪️ 위와 같은 원인
  4. 압축
    ▪️ styled component는 기본적으로 css를 압축하여 js에 넣음
  5. 상태 공유 어려움
    ▪️ component의 상태와 style 상태를 맞추기 위해서
  6. 순서와 명시도
  7. 캡슐화

🔗 관심사의 분리 (Separate of Concerns)

Button, DATE Packer, Modal 등은 각각 JS, CSS, HTML이 같은 곳에 모여있거나 또는 영향을 주고 받는 상태를 캡슐화하여 상태 공유를 제한하는 것이 좋음
이 목적하에서 styled component 적용함
styled component를 아래 명령어로 설치한다

npm install styled-components --save


📁 테마

📌 theme

  1. UI, UX의 일관성 유지
  2. 유지보수가 용이
    ▪️ 디자인을 담고 있는 테마 파일과 기능을 담고 있는 컨포넌트들을 분리함으로써 유지보수가 용이해짐
  3. 확장성
  4. 재사용성
  5. 사용자 정의

📌 styled components theme 구성

  • theme provider
    • theme provider 하위에 component 위치
    • component : 프로젝트를 구성하고 있는 컴포넌트들이 배치되어 있음
    • theme 파일들로 테마 설정


📁 테마스위처 context API

📌 Theme Switcher with Context API

  1. 사용자는 토글 UI를 통해 웹 사이트의 색상 테마를 바꿀 수 있다.
  2. 색상 테마는 전역 상태로 존재한다.
  3. 사용자가 선택한 테마는 로컬 스토리지에 저장한다.

📌 정리

createContext를 이용하여 context 틀을 만듦. context는 wrapper로 생각하면 됨. Provider 하위의 컴포넌트들이 이를 구독하고 언제든지 꺼내쓸 수 있음. (useContext라는 hook을 사용함)

0개의 댓글