2024.02.21(수)
특징 | ⚛️Create React App(CRA) | ⚡Vite |
---|---|---|
빌드 도구 | webpack | ESBuild |
언어 | JavaScript (Node.js) | Golang |
서버 | Express | Koa |
빌드 | Source build | Module build |
환경 변수 접근 | process.env.KEY | import.meta.env.KEY |
Hot Module Replacement (HMR) | 지원 | 지원 |
장점 | 간편한 설정: 초기 설정을 자동화하여 React 애플리케이션을 빠르게 시작 가능 | 빠른 빌드 속도: ESBuild를 사용하여 빠른 모듈 번들링을 제공하므로 초기 빌드 및 개발 서버의 성능이 우수 |
단점 | 느린 빌드 속도: 큰 규모의 프로젝트에서는 빌드 속도가 느릴 수 있음 | 상대적으로 새로운 도구: 지원 및 커뮤니티가 CRA보다는 상대적으로 작음 |
npx create-react-app my-app --template typescript
cd my-app
npm start
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev
💡 실제로 둘 다 설치해보니 설치부터 서버 시작까지 걸리는 시간이 Vite가 훨씬 빠른 것을 확인할 수 있었다.
Directory | Description |
---|---|
pages | 라우트에 대응하는 페이지 컴포넌트(컨테이너) |
components | 공통 컴포넌트 및 각 페이지에서 사용되는 컴포넌트 |
utils | 유틸리티 |
hooks | 리액트 훅 |
model | 모델(타입) |
api | API 연동을 위한 fetcher 등 |
"typecheck": "tsc --noEmit --skipLibCheck"
npm run typecheck
로 사용 가능tsc
: TypeScript Compiler--noEmit
: JavaScript 파일을 생성 ❌--skipLibCheck
: 라이브러리 파일에 대한 유형 검사를 건너뛰기src/components/layout/Layout.tsx
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;
💡 JSX Element ⊂ React Element ⊂ React Node
React.ReactNode
: 모든 유형 가능
interface ModalRendererProps {
title: string;
children: React.ReactNode;
}
React.ReactElement
: JSX element만 가능
interface ModalRendererProps {
title: string;
children: React.ReactElement;
}
모든 HTML 요소에 대한 기본 스타일을 초기화시키는 스타일 시트
브라우저의 기본 스타일을 완전히 제거하지 않고 각 요소를 표준화시켜 브라우저 간의 스타일 차이를 보완하는 스타일 시트
normalize.css의 발전된 버전
- 설치:
npm install sanitize.css --save
- 적용:
import "sanitize.css";
function Header() {
return (
<header>
<h1>Book Store</h1>
</header>
);
}
export default Header;
import styled from "styled-components";
function Header() {
return (
<HeaderStyle>
<h1>Book Store</h1>
</HeaderStyle>
);
}
const HeaderStyle = styled.header`
background-color: #333;
h1 {
color: white;
}
`;
export default Header;
💡 보통 styled components 코드의 길이도 길기 때문에 파일을 분리하여 작성한다고 함
src/style/global.ts
import "sanitize.css";
import { createGlobalStyle } from "styled-components";
import { ThemeName } from "./theme";
interface Props {
themeName: ThemeName;
}
export const GlobalStyle = createGlobalStyle<Props>`
body {
padding: 0;
margin: 0;
}
h1 {
margin: 0;
}
* {
color: ${
({themeName}) => (themeName === "light") ? "black" : "white"
};
}
`;
src/style/theme.ts
Theme의 color 정의 방법
export type ThemeName = "light" | "dark";
interface Theme {
name: ThemeName;
color: {
[key: string]: string;
};
}
export type ThemeName = "light" | "dark";
type ColorKey = "primary" | "background" | "secondary" | "third";
interface Theme {
name: ThemeName;
color: {
[key in ColorKey]: string
}
}
ColorKey 타입에 있는 각 문자열 리터럴을 반복하여 해당 문자열 리터럴을 키로 갖는 객체를 생성
color: {
primary: string;
background: string;
secondary: string;
third: string;
}
Utility Types: Record<Keys, Type>
export type ThemeName = "light" | "dark";
type ColorKey = "primary" | "background" | "secondary" | "third";
interface Theme {
name: ThemeName;
color: Record<ColorKey, string>;
}
Keys
: 키 집합을 나타내는 타입 (여러 개 가능)
Type
: 각 키에 대응하는 값의 타입 (단일 값)
⇒ 각 키는 주어진 값 타입에 매핑됨
export type ThemeName = "light" | "dark";
type ColorKey = "primary" | "background" | "secondary" | "third";
interface Theme {
name: ThemeName;
color: Record<ColorKey, string>;
}
export const light: Theme = {
name: "light",
color: {
primary: "brown",
background: "lightgray",
secondary: "blue",
third: "green",
}
};
export const dark: Theme = {
name: "dark",
color: {
primary: "coral",
background: "midnightblue",
secondary: "darkblue",
third: "darkgreen",
}
};
src/App.tsx
import Layout from "./components/layout/Layout";
import Detail from "./pages/Detail";
import Home from "./pages/Home";
import { GlobalStyle } from './style/global';
import { ThemeProvider } from "styled-components";
import { dark, light } from "./style/theme";
function App() {
return (
<ThemeProvider theme={light}>
<GlobalStyle themeName="light"/>
<Layout>
<Home />
{/* <Detail /> */}
</Layout>
</ThemeProvider>
);
}
export default App;
실제 theme은 state를 사용해서 사용자에게 입력받을 예정