1. Create React App 환경 만들기
CRA(Create React App)란?
Single-page application(SPA)으로, 하나의 HTML 페이지와 애플리케이션 실행에 필요한 JS와 CSS 같은 모든 자산을 로드하는 애플리케이션이다. CRA 공식 홈페이지에서는 CRA에 대해 다음과 같이 설명하고 있다.
- Less to Learn
- Only One Dependency
- No Lock-In
CRA는 개발자가 개발에만 집중할 수 있게 자동으로 최적화해주고, 하나의 빌드 종속성을 가지며, 다양한 패키지를 사용하여 프로젝트 개발을 할 수 있다.
CRA 환경 세팅
1) react 앱 환경을 먼저 만들고
npx create-react-app my-app
cd my-app
npm start
새로운 React 앱 만들기 – React
A JavaScript library for building user interfaces
ko.legacy.reactjs.org
2) 타입스크립트 기반 프로젝트를 생성했다.
npx create-react-app todolist --template typescript
--template 명령어로 타입스크립트 기반 프로젝트를 만들면 확장자가 .tsx로 생성된 것을 확인할 수 있다.
CRA와 Vite
이번에는 CRA를 사용했지만, Vite를 사용할 수도 있다. CRA는 webpack으로 전체를 번들링하고, Vite는 처음 이후에는 esbuild를 이용해서 변경된 부분만 새로 번들링한다. 사용하는 서버의 크기도 차이가 있어 Vite의 속도가 빠르다.
CRA는 많은 기능들이 포함되어 편하게 개발이 가능하지만 그만큼 속도가 느릴 수밖에 없다. 하지만 Vite를 사용한 프로젝트는 그 규모가 커지면 커질수록 CRA를 사용한 프로젝트 보다 빌드 속도가 빠르다. Vite를 사용하는 방법도 고려해보자.
2. 클래스형 컴포넌트와 함수형 컴포넌트
클래스형 컴포넌트
리액트 초기에 많이 사용했던 컴포넌트 생성 방식이다. (export하는 것도 잊지 말자.)
import { Component, ReactNode } from "react";
class ClassCom extends Component {
render(): ReactNode {
return <div>클래스형 컴포넌트</div>;
}
}
export default ClassCom;
컴포넌트를 생성하고 App.tsx에 import 했다.
import ClassCom from "./ClassCom";
호출할 때는 아래 Line 4와 같이 하면 된다.
function App() {
return (
<div className="container">
<ClassCom></ClassCom>
</div>
);
}
함수형 컴포넌트
최근 리액트에서 선호하는 방식이다. 클래스형 컴포넌트가 class 키워드로 시작한 것처럼 함수형 컴포넌트는 function으로 시작한다. 그리고 클래스형 컴포넌트에서 render라는 메소드를 사용한 것과 달리 함수형 컴포넌트는 바로 return을 사용하면 return 안의 내용이 rendering되는 형태이다.
import React from "react";
const FuncCom = () => {
return <div>함수형 컴포넌트</div>;
};
export default FuncCom;
그리고 클래스형 컴포넌트와 마찬가지로 import하고 호출해서 사용한다.
3. state
리액트에서는 변수 대신 state를 사용한다. state는 데이터의 상태를 의미하고, 데이터의 동적인 감시가 가능하다. useState를 사용한다.
4. React.FC
FC란 function component 타입의 줄임말로, 리액트 + 타입스크립트 조합으로 개발할 때 사용하는 타입이다. 함수형 컴포넌트 사용 시 타입 선언에 쓸 수 있도록 리액트에서 제공하는 타입이다.
단점
1. props가 기본적으로 선언되어 있어, 이를 사용하는 것보다 명시적으로 선언하여 사용하는 것이 더 안전하다.
2. defaultProps의 오버라이딩에 문제가 생길 수 있다.
6. Todolist 만들기
map
map으로 데이터 반복을 처리했다.
import React, { useState } from "react";
type Todo = {
id: number;
text: string;
isChecked: boolean;
};
const Todolist: React.FC = () => {
const title: string = "오늘 할일";
const [todos, setTodos] = useState<Todo[]>([
{ id: 1, text: "공부하기", isChecked: false },
{ id: 2, text: "잠자기", isChecked: false },
{ id: 3, text: "미팅하기", isChecked: false },
]);
return (
<div>
<h1>{title}</h1>
<p></p>
<div className="container">
<div className="board">
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo.text}</li>
))}
</ul>
</div>
</div>
</div>
);
};
export default Todolist;
삼항연산자
삼항 연산자로 체크박스를 구현했다.
import React, { useState } from "react";
type Todo = {
id: number;
text: string;
isChecked: boolean;
};
const Todolist: React.FC = () => {
const title: string = "오늘 할일";
const [todos, setTodos] = useState<Todo[]>([
{ id: 1, text: "공부하기", isChecked: false },
{ id: 2, text: "잠자기", isChecked: false },
{ id: 3, text: "미팅하기", isChecked: false },
]);
const handleCheckedChange = (itemId: number) => {
setTodos((prevItems) =>
prevItems.map((item) =>
item.id === itemId ? { ...item, isChecked: !item.isChecked } : item
)
);
};
return (
<div>
<h1>{title}</h1>
<div className="container">
<div className="board">
<ul>
{todos.map((todo, idx) => (
<li key={todo.id}>
<input
type="checkbox"
onChange={() => handleCheckedChange(todo.id)}
/>
{todo.isChecked ? (
<del>{todo.text}</del>
) : (
<span>{todo.text}</span>
)}
</li>
))}
</ul>
</div>
</div>
</div>
);
};
export default Todolist;