React/Next/TS 기본 개념 및 사용이유
2025. 6. 22. 18:57ㆍWeb_Programming
React란?
사용자 인터페이스 구축을 위한 JavaScript 라이브러리
등장 배경
기존의 UI 구현 방식의 한계
명령형 방식 + jQuery
$('#button').click(function() {
$('#modal').show();
});
- 직접 절차적으로 명시
- 상태 변화에 따른 DOM 조작 직접 관리
- => 로직이 복잡하고 버그가 발생하기 쉬움
- => 상태와 UI 간의 일관성 유지가 어려움
React의 주요 특징 및 해결책
선언형 프로그래밍
- “무엇을 보여줄 것인가”를 선언하면, React가 UI를 알아서 그려줌
- 상태가 변하면 UI를 자동으로 다시 렌더링
- 복잡한 DOM 조작을 직접 하지 않아도 됨
// Vanila JS
const list = document.getElementById("list");
const item = document.createElement("li");
item.textContent = "Apple";
list.appendChild(item);
//JQuery
$('#button').click(function() {
$('#modal').show();
});
//React
function FruitList({ fruits }) {
return (
<ul>
{fruits.map(fruit => <li key={fruit}>{fruit}</li>)}
</ul>
);
}
구분 | 명령형 | 선언형 (React) |
접근 방식 | 어떻게 할 것인가 | 무엇을 할 것인가 |
예시 | DOM 직접 조작 | JSX로 UI 선언 |
상태 변화 반영 | 수동 | 자동 (React가 처리) |
유지보수성 | 낮음 | 높음 |
가상 DOM
- 이전 가상 DOM과 비교하여 차이점만 실제 DOM에 반영 (최소 단위 변경)
- JSX 트리 => 가상돔 => 이전 가상돔과 비교 => 렌더
컴포넌트 기반 구조
- UI를 재사용 가능한 컴포넌트 단위로 분리
- 모듈화, 유지보수, 테스트, 협업에 용이
<div id="app"></div>
<script>
$(document).ready(function () {
const $button = $('<button></button>')
.text('Click me')
.on('click', function () {
alert('Clicked!');
});
$app.append($button);
});
</script>
// Button.jsx
export default function Button({ label, onClick }) {
return <button onClick={onClick}>{label}</button>;
}
// App.jsx
import Button from './Button';
export default function App() {
return (
<div>
<h1>Welcome</h1>
<Button label="Click me" onClick={() => alert("Clicked!")} />
</div>
);
}
단방향 데이터 흐름
- 상위 부모컴포넌트 => 하위 자식 컴포넌트로 props를 통해 전달, 반대로는 전달할 수 없다
- 데이터 흐름이 예측 가능하고, 디버깅이 용이함
구현
컴포넌트
import React, { useState } from 'react';
interface Props{
name:string;
age:number;
}
export default function Greeting({ name, age, children }:propsWithChildren<Props>) {
const [isHello, setIsHello] = useState(true);
const ref = useRef(true);
const toggleGreeting = useCallback(() => {
setIsHello(prev => !prev);
},[]); //마운트 시점만 생성
const data = useMemo(()=>{
return 1+1;
},[isHellow]); //isHellow 변경 시점 마다 재연산.
useEffect(() => {
console.log("마운트");
setIsHello(false);
ref.current = false
console.log(isHello, ref.current); //true, false
return () => {
console.log("언마운트");
};
}, []);
return (
<div>
{children}// 자식
<h1>{isHello ? `${name} Hello!` : `${name} Goodbye!``}</h1>
<button onClick={toggleGreeting}>Toggle</button> //toggleGreeting 생성마다 리렌더링.
</div>
);
}
// <Greeting name={"이름"} age={12}>{"자식"}</Greeting>
속성값 (Props)과 상태값 (State)
- Props: 부모 컴포넌트로부터 전달받은 불변 데이터
- 하위 컴포넌트에서는 변경이 불가능합니다.
- State: 컴포넌트 내부에서 관리하는 가변 데이터
Hook
주요 내장 Hook
- useState https://ko-react-exy5xcwjj-fbopensource.vercel.app/reference/react/useState
- useEffect https://ko-react-exy5xcwjj-fbopensource.vercel.app/reference/react/useEffect
- useRef https://ko-react-exy5xcwjj-fbopensource.vercel.app/reference/react/useRef
커스텀 훅 구현 방법
// useCount.js
import { useState } from 'react';
export default function useCount({
initialValue = 0,
}: {
initialValue: number;
}) {
const [count, setCount] = useState(initialValue);
const increase = () => setCount((prev) => prev + 1);
const decrease = () => setCount((prev) => prev - 1);
const reset = () => setCount(initialValue);
return { count, increase, decrease, reset };
}
Next.js란?
React를 기반으로 한 웹 애플리케이션 프레임워크입니다.
특히 SSR, SSG(정적 페이지), Server Components 등 기능을 제공하여, React의 단점을 보완
1. 등장 배경
React의 한계
- CSR 중심 구조
- 페이지 로딩 시 자바스크립트를 모두 다운로드 후 렌더링 → 초기 로딩 지연, SEO 취약.
2. 주요 특징 및 React 한계 해결책
1. Server Components
- React Server Components (RSC) 지원
//page.tsx
import LikeButton from '@/app/ui/like-button'
import { getPost } from '@/lib/data'
export default async function Page({ params }: { params: { id: string } }) {
const post = await getPost(params.id)
return (
<div>
<main>
<h1>{post.title}</h1>
{/* ... */}
<LikeButton likes={post.likes} />
</main>
</div>
)
}
//link-button.tsx
'use client'
import { useState } from 'react'
export default function LikeButton({ likes }: { likes: number }) {
// ...
}
2. App Router
- app/ 디렉토리 기반의 최신 파일 라우팅 방식.
- https://nextjs.org/docs/app/getting-started/layouts-and-pages
3. 서버 기능 통합
- API Routes, Middleware 등을 통해 백엔드 없이도 API 구축 가능.
4. SEO 친화적
- 페이지를 미리 렌더링(SSR/SSG)하여 검색 엔진 최적화에 강력.
5. 성능 최적화 내장
- 코드 스플리팅, 이미지 최적화(next/image), 폰트 최적화 등 자동 제공.
전역 상태 관리
React 내장 전역 상태: useContext
- Context API를 통해 전역 상태 생성 가능
export const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
// App.jsx
const { theme, setTheme } = useContext(ThemeContext);
provider 하위는 context 변경마다 모두 리렌더링되어 비효율적.
Zustand
기본 특징
- 패키지 사이즈가 가볍고, 빠른 전역 상태 관리 라이브러리
- 간편화된 redux
Jotai
기본 특징
- 원자(atom) 단위로 상태를 정의하는 상태 관리.
- 내부적으로 Recoil과 유사한 개념, 훨씬 더 간단하고 유연.
- Context 없이도 Scoped 상태와 동적 상태 표현 가능.
프로젝트 내 사용 예시
- 도메인 하위에서 여러 state 관리 ⇒ zustand
- 단일 state 및 state 적용 범위가 적은 경우 ⇒ jotai
tanstack/react-query
1. 기존 방식의 문제점
- 로딩/에러 처리 반복 코드 많음
- 캐싱, 리패칭, 백그라운드 갱신, 쿼리 무효화 등 수동 처리
- 서버 상태 공유 어려움
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
fetch('/api/data')
.then(res => res.json())
.then(setData);
.catch((e)=>{
setError(error);
})
.filnally(()=>{
setLoading(false);
})
}, []);
import { useQuery } from '@tanstack/react-query';
function MyComponent() {
const [enabled, setEnabled]=useState(false);
const { data, isLoading, error, refecth } = useQuery({
queryKey: ['posts'],
queryFn: () => fetch('/api/posts').then(res => res.json()),
enabled: enabled
refechOnWindowFocus:true
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error occurred</p>;
return (
<>
<button onClick={()=>setEnabled(true)}>fetch</button>
<ul>
{data.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
</>
);
}
2. tanstack Query의 주요 특징
기능 | 설명 |
자동 캐싱 | 동일 요청은 자동 캐시, 빠른 화면 전환 |
자동 리패칭 | refetch, focus 시 갱신 등 |
쿼리 무효화 | 데이터 갱신 시 쿼리 갱신 |
로딩/에러/성공 상태 관리 | isLoading, error, data 등 |
TypeScript
JS 한계
타입 검사 | 없음 (런타임 오류 발생 가능) |
에디터 지원 | 비교적 약함 |
코드 명확성 | 추측 필요 |
협업 | 의도 파악 어려움 |
리팩토링 | 타입 정보 부족으로 위험 |
TypeScript를 쓰는 이유
1. 정적 타입 검사
- 오류를 사전에 잡을 수 있음
- 런타임이 아니라 코드 작성 시점에 오류 감지
- 예: 잘못된 파라미터 타입, 오탈자 등
function greet(name: string) {
console.log('Hello, ' + name);
}
greet(123); // 컴파일 에러 발생
2. 개발 편의
- 자동 완성 (auto-completion)
- 타입 추론, 타입 정보 제공 (hover 시)
- 코드 리팩토링 지원 강화
3. 가독성과 유지보수성 향상
- 함수의 입력/출력 타입을 명시함으로써, 협업 시 함수 사용법이 명확해짐
- API 응답 구조, 객체 구조 등이 명시되어 있어 추측 없이 개발 가능
반응형
'Web_Programming' 카테고리의 다른 글
[디자인 패턴] 반복자 패턴_Iterator pattern (JavaScript) (0) | 2024.11.17 |
---|---|
[디자인 패턴] 방문자 패턴_ Visitor pattern (JavaScript) (0) | 2024.11.17 |
[디자인 패턴] 복합체 패턴_ Composite pattern (JavaScript) (0) | 2024.11.17 |
[디자인 패턴] 플라이웨이트 패턴_ Flyweight pattern (JavaScript) (0) | 2024.11.17 |
[디자인 패턴] 관찰자 패턴_Observer pattern (JavaScript) (0) | 2024.11.17 |