신한투자증권 프로 디지털 아카데미 (프디아) 6기 교육 중 배운 내용을 작성한 글입니다
Day 32 (202506012)
이전에 만들었던 Todo App에 스타일을 적용하고,
TypeScript로 바꿔서 다시 만들어보는 과정을 진행하였다.
TypeScript는 javaScript에 타입이 추가된 형태라고 생각하면 된다.
TypeScript에 대한 기본 문법에 대해 알기 위해서 이전에 작성하였던 글을 첨부하겠다
(이전 글 참고)
[신한투자증권 프로디지털아카데미] 클라우드 기반 프론트엔드 기초 프로그래밍 - 5 (TypeScript & Re
신한투자증권 프로 디지털 아카데미 (프디아) 6기 교육 중 배운 내용을 작성한 글입니다Day 27 (20250604) TypeScriptI/O가 대부분의 병목을 차지함자바스크립트에서 Type을 추가한 언어이다. (자바스크립
tyvkwygk.tistory.com
스타일 컴포넌트 적용하기
리액트에서 스타일 컴포넌트를 적용하는 방법에 대해 설명하기 이전에
HTML에서 CSS를 적용하는 적용하는 방법에 대해 복습하겠다.
HTML/CSS 에서 CSS 적용하는 방법
- Inline style 로 적용 (style 속성)
- css 파일 분리하여 적용(html에서 class, id 속성 등 이용)
- html 내에서 style 태그 이용
React에서 css 적용
- Inline style 적용
- css 파일 분리하여 적용 (JSX className 사용)
- CSS-IN-JS (Javascript내에서 css 적용하여 컴포넌트 만드는 방법)
- (optional) : utility css 라이브러리 사용 (tailwind css 사용)
일반 CSS → 모듈 CSS → STYLE 컴포넌트 → tailwind css 순으로 발전했음
리액트는 자바스크립트 로드가 끝나야 HTML 그리는데
걔네 사이즈가 막 3MB 되봐봐 랜더링 하는데 오래걸리겠지. (번들링 크기가 커져서 랜더링이 오래 걸린다)
styled-compoent 사용
설치
npm install styled-components
styled-components 공식문서
styled-components: Documentation
styled-components: Documentation
Learn how to use styled-components and to style your apps without stress
styled-components.com
tailwind css 사용
설치
npm install tailwindcss
vite라면 아래도 설치
npm install @tailwindcss/vite
TailwindCSS는 Utility-First CSS 프레임워크. 미리 정의된 클래스들을 조합하여 빠르게 UI를 구축할 수 있습니다.
특징
- 유틸리티 우선: 작은 단위의 클래스들을 조합
- 반응형 디자인: 모바일 우선 접근법
- 커스터마이징 가능: 디자인 시스템 구축 용이
- 번들 크기 최적화: 사용하지 않는 CSS 자동 제거
tailwindcss 공식문서
Installing with Vite - Installation
Installing with Vite - Installation
Integrate Tailwind CSS with frameworks like Laravel, SvelteKit, React Router, and SolidJS.
tailwindcss.com
vite에서 설정
- 먼저 vite.config.js 파일에 tailwindcss import 해주고 풀러그린에 tailwindcss() 추가해준다
2. index.css 있는 구조 층에 index.css 지우고 tailwindcss import 해준다 (App.js나 main.jsx에서 import 하기)
특히 shadnc-ui 에서 tailwindcss 많이 쓰는 걸 볼 수 있다.
Build your Component Library - shadcn/ui
A set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.
ui.shadcn.com
예를 들어
https://ui.shadcn.com/docs/components/breadcrumb
Breadcrumb
Displays the path to the current resource using a hierarchy of links.
ui.shadcn.com
이런거 보면 파일들이 tailwindcss로 이루어져 있는 걸 볼 수 있다.
외우려고 하지 말고, 컨셉 이해하고 구성요소가 어떻게 돌아가는지 보면서 외우는 게 좋을 것이다
cf. Tailwind CSS IntelliSense → extension 설치 하면 색깔 뜨는 거 보임


tailwindcss가 컴파일 과정에서 쓰는 애들만 남기고 나머지 다 버려준다. <사용하지 않는 CSS 자동 제거 >
tailwind는 css 이기 때문에 자바스크립트에 영향을 주지 않겠다 vs styled components의 경우에는 번들링 크기에 영향을 많이 주었었음
- 자바스크립트 파일은 브라우저 레벨에서 캐싱을 지원한다.
- css 파일을 분리해서 작성할 수 있다는 점은 조직이 클 때 업무를 분리해서 할 수 있다는 말과 같으니까 상황에 맞게 사용하면 좋을 것 같다
React Advanced - 더 다양한 Hook들
이 부분은 최신 Hook들에 대해서 이야기 하고 있는데 useTransition, useActionState 정도는 나중에 프로젝트 진행할 때 사용할 수도 있을 것 같다.
코드 분할 (Suspense와 코드분할)
리액트는 코드 그리는 걸 자바스크립트에서 한다.
link 태그나 스타일 태그 불러서 요청을 보내고 react 파일 로딩이 끝나면 그제서야 그림을 그린다.
자바스크립트 파일 커지면 로딩시간이 오래걸릴거야
문제점 발생
사용자의 인터넷환경 (개선불가), 번들크기(자바스크립트 파일크기)가 크다 → 자바스크립트 파일 크기를 줄이자! → 3MB 하나 말고 1 MB 파일 3개로 쪼개고 1 MB 파일 3개를 동시에 불러오자 → 로딩속도가 빨라질 수 있겠다
그래서 나온 개념이 코드 분할
코드 분할(Code Splitting)
그냥 import 하면 오는 js 파일이 1개가 옴. 자바스크립트 파일 하나 온다. 걔를 로드 하는 순간 그림을 그리기 시작한다.
근데 lazy 사용하여 코드 분할 하게 된다면
npm run build 빌드하면 dist 폴더가 하나 생기게 됨. (이게 우리가 만든 실제 react production으로 동작하게 됨)
dist에 있는 index.html 저 dist 파일 주면 알아서 자바스크립트 실행되는데
npm run preview(실제 환경이랑 똑같이 보기 위해서? )
그 후 4173번 포트로 가면 뜨는데 개발자모드에서 network 탭 보면 됨
코드 분할 (Lazy 사용) -> 동적 코드 분할
const LazyComponentOne = lazy(() => import("./LazyComponentOne"));
const LazyComponentTwo = lazy(() => import("./LazyComponentTwo"));
동적 import를 사용했을 경우 (원래는 기본적으로 자바스크립트 ㄹ파일 하나 나오고 그거 다 끝내면 그림을 그리기 시작하는데)
하나의 자바스크립트 파일을 분할하여 제일 중요한 거 하나만 먼저 보여주자

Lazy1 그 버튼을 누른 순간 이제서야 LazyComponentOne 파일을 보여줄거야.


그리고나서 Lazy1 다시 요청하면 이미 불러왔으니까 또 요청하지는 않아.
자바스크립트에서 코드 분할해서 동작하고, 그 필요할 때 불러오자.
그리고 그 아직 Lazy1이 도착하지 않았을 때 로딩중.. 이런거 뜨게 하는 역할을 하는 게 Suspense
fallback 인자 하나 받고, 거기에 저 응답 도착하지 않았을 때 쓸 말 써놓으면 됨.
<Suspense fallback={<div>로딩중...</div>}>
{showLazy1 && <LazyComponentOne />}
{showLazy2 && <LazyComponentTwo />}
{!showLazy1 && !showLazy2 && <p>표시할 기능이 없습니다.</p>}
</Suspense>
코드 분할 하지 않고 그냥 import 한 경우

import LazyComponentOne from "./LazyComponentOne";
import LazyComponentTwo from "./LazyComponentTwo";

이건 하나의 자바스크립트 파일 안에 모든 기능이 다 있고, Lazy1을 누른다고 해서 뭐 다른 파일이 import 되지는 않는다. 그 차이!
https://xtring-dev.tistory.com/entry/Reactjs-코드-분할Code-Splitting-React-더-잘-사용하기
[React] 코드 분할(Code Splitting) - React 더 잘 사용하기
https://ko.reactjs.org/docs/code-splitting.html 코드 분할 – React A JavaScript library for building user interfaces ko.reactjs.org Code Splitting은 왜 필요할까? 최근 높은 인터넷 속도와 좋은 프로세서가 일반화 되면서 웹서
xtring-dev.tistory.com
use
Hook은 컴포넌트 최상단에서만 쓸 수 있다.
(ex) if문 안에서 Hook 못쓰지? ㅇㅇ useEffect, useCallback 등등 분기 때문에실행되는 게 아니라 무조건 한번 mount 될 때 실행되어야 하기 때문에!)
근데 use는 Hook 이 아니라 함수다. promise나 context를 읽어오게 하는 함수. (코드 블럭 안에서도쓸 수 있음)
use: Context 혹은 Promise를 기다린 후 사용.
단점 : props로 promise를 전달해야 해서 아마 쓰기 조금 힘들 수도 있다
useReducer (컴포넌트 외부 상태관리)
컴포넌트 바깥에서 상태관리를 하려고 하다 보니까 ui와 코드를 분리하려고 사용?
현업에서 잘 안씀. 이걸 직접적으로 사용하는 프로젝트는 본 적 없음
Transition과 default value
useTransition: UI의 일부를 백그라운드에서 렌더링 할 수 있도록 함. (업데이트 작업을 후순위로 미룬다.)
어떤 비동기작업이 실행될 때 state가 변하면 계속 다시 그려야 하니까
useDeferredValue: 특정 변수의 UI업데이트를 늦추자.
DOM과 Virtual DOM 과 JS Component
Dom (Document Object Model)
(HTML 이라고 생각하면 됨! 보이는 건 DOM이다)
브라우저가 렌더링하는 실제 HTML 구조
화면에 보이는 UI 요소들
Virtual Dom
(실제 dom 대신 관리하는 객체로 "다시 그린다"는 말은 virtual dom을 다시 그린다는 말이다)
실제 DOM의 복사본 (메모리 상의 객체 트리)
변경이 감지되면 diff 알고리즘을 통해 실제 DOM과 비교
( 리액트는 Virtual DOM을 기반으로 최적화된 렌더링을 제공한다)
JS Component
UI 단위 블록
내부적으로 state, props, 변수 등을 관리
상태에 변화가 발생하면 → 비교한 뒤 가상 DOM 재생성
이후 diff 알고리즘을 통해 실제 DOM 업데이트
작동 흐름
1. 상태(state) 변경 → 무조건 바로 렌더링될까?
- React에서 state가 바뀌면 Virtual DOM을 새로 만듦
- 하지만 매번 실제 DOM까지 바로 반영되진 않는다 (렌더링[그림을 그리는 과정은] 비용이 큰 작업이기 때문에)
2. Virtual DOM과 Real DOM 비교: Diffing 알고리즘 사용
- render() 함수 → JSX → Virtual DOM
- React는 이전 Virtual DOM과 현재 Virtual DOM을 비교(diff)
- 변경된 부분만 실제 DOM에 최소한으로 반영
3. 상태 변경 → 즉시 DOM 반영 되지 않음 → 일괄 처리(Batching)
- setState()는 바로 DOM 업데이트 하지 않음
- 내부적으로 "스케줄링"해서 → 작업이 다 끝나면 한 번에 처리 (이런 걸 batching or deferred rendering 이라고 함)
4. 너무 잦은 state 변경은 성능 문제를 유발함
- 사용자가 타이핑, 스크롤 등 할 때마다 state 변경?
- 이때마다 Virtual DOM 비교 & 렌더링? → 너무 비효율적
- 그래서 성능 개선 기술들이 등장
성능 최적화 기술
Batching | 여러 상태 변경을 모아서 한 번에 처리 |
Transition | 우선순위 낮은 작업은 나중에 렌더링 (예: 자동완성 리스트 등) |
useTransition | 상태 업데이트를 "지연 처리"하도록 React에 알려줌 |
useDeferredValue | 특정 값 자체를 "느리게 업데이트" (입력창 등에서 자주 사용) |
Suspense / lazy | 비동기 컴포넌트 로딩 최적화 |
lifecycle | 클래스 컴포넌트에서 성능 조절 (ex. shouldComponentUpdate) |
결론
1. state 변경 → Virtual DOM 재생성
2. diff 알고리즘으로 실제 DOM과 비교
3. 변경된 부분만 최소 반영
4. 너무 자주 바뀌는 상태는 transition이나 batching으로 최적화
debounce : 일정 시간 내에 반복된 호출을 1회만 처리할 때 최적화를 목적으로 사용한다.
예시코드
// ex) 300ms 동안 입력이 멈출 때만 호출
function debounce(callback, delay) {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
callback(...args);
}, delay);
};
}
[React] 검색에서 Debounce 적용해보기
debounce와 throttle을 공부하고, 검색기능을 만들면서 debounce를 적용한 이야기
velog.io
HOC (매커니즘이 중요함)
함수를 함수로 바라보자 (데이터 타입으로 바라보자)
컴포넌트 또한 함수임
import React from "react";
export default function UserDisplay({ user }) {
return (
<div>
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
</div>
);
}
이런 컴포넌트를 재사용할건데
시나리오
유저를 props로 받아서 끝 → 얠 재사용할건데 withUser
유저가 다양한 소스에 있을 수 있음.
withUser 의 return 타입은 함수네 (props를 받아서 ui를 return 하고 있음→ 컴포넌트임)
jsx에서 쓸 수 있기 때문에 인자도 여기서는 컴포넌트야
HOC는 컴포넌트를 인자로 받아서 컴포넌트를 return 하는거야
withUser의 인자는 컴포넌트고 return 타입도 컴포넌트야.
const UserDisplayWithUser = withUser(UserDisplay);
얘 UserDisplayWithUser는 props로 userId를 받지.
import React from "react";
export default function UserDisplay({ user }) {
return (
<div>
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
</div>
);
}
여기서 userId 직접 받아서 useEffect 써도 되긴 되지.
근데 굳이 이렇게 한 이유는 User를 주입해주는 컴포넌트가 많으니까 같
은 코드 여러 번 들어가는 거 싫어서 기능 분리하기 위해서 이렇게 함.
유저 주입해주는 컴포넌트 하나 만들어서,, 이렇게 씀.
관례상 HOC(Higher order component) with ~~~ 라고 함.
훅은 use ~~~ 라고 하는 것처럼
useState, useEffect 만 잘써도 리액트는 끝나..
useCallback, useMemo 정도까지는 알고 있는 게 좋다.
toDo 다시 아예처음부터 다시해봐
wsl, 리눅스에서는 가능함.
나 어떤 타입을 쓸 지 잘 모르겠어.
generic으로 선언 해줘야함
(typeof COLORS)[number]
보통 위 방법 많이 씀
const [todoList, setTodoList] = useState<Todo[]>([]);
js와 tsx의 차이점은 state의 typing, props의 typing 만 다름!!!
inferface와 type 똑같이 사용 가능한데,, 타입스크립트에서는 interface로 하는 걸 권장하지만, 둘다 똑같이 동작함