Contents
see List작성일 2025. 11. 30.
React 18 Concurrent Features
React 18에서 도입된 Concurrent Rendering은 React가 여러 버전의 UI를 동시에 준비할 수 있게 해주는 핵심 기능입니다. 사용자 경험을 크게 향상시키는 새로운 훅과 API를 제공합니다.
언제 사용하나요?
- 대규모 리스트 렌더링 시 입력 지연 방지
- 페이지 전환 시 이전 페이지를 유지하며 로딩
- 검색 자동완성 등 빈번한 상태 업데이트
- 사용자 인터랙션 우선순위 관리
React 18 업그레이드
// React 18 설치
npm install react@18 react-dom@18
// index.js 변경
import { createRoot } from "react-dom/client";
const container = document.getElementById("root");
const root = createRoot(container);
root.render(<App />);useTransition - 우선순위 낮추기
import { useState, useTransition } from "react";
function SearchPage() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
// 긴급: 입력값 즉시 업데이트
setQuery(e.target.value);
// 낮은 우선순위: 검색 결과 업데이트
startTransition(() => {
setResults(searchItems(e.target.value));
});
};
return (
<div>
<input value={query} onChange={handleChange} />
{isPending ? (
<div>검색 중...</div>
) : (
<ResultList results={results} />
)}
</div>
);
}useDeferredValue - 값 지연
import { useDeferredValue, useMemo } from "react";
function ProductList({ searchQuery }) {
// searchQuery의 지연된 버전
const deferredQuery = useDeferredValue(searchQuery);
// 실제 필터링은 지연된 값으로
const filteredProducts = useMemo(
() => products.filter(p =>
p.name.includes(deferredQuery)
),
[deferredQuery]
);
// 지연 중일 때 시각적 피드백
const isStale = searchQuery !== deferredQuery;
return (
<div style={{ opacity: isStale ? 0.5 : 1 }}>
{filteredProducts.map(p => (
<ProductCard key={p.id} product={p} />
))}
</div>
);
}Suspense 향상
import { Suspense, lazy } from "react";
const Comments = lazy(() => import("./Comments"));
const Sidebar = lazy(() => import("./Sidebar"));
function App() {
return (
<div>
<Header />
<Suspense fallback={<Spinner />}>
<main>
<Content />
<Suspense fallback={<CommentSkeleton />}>
<Comments />
</Suspense>
</main>
<Suspense fallback={<SidebarSkeleton />}>
<Sidebar />
</Suspense>
</Suspense>
</div>
);
}Automatic Batching
// React 18에서는 모든 업데이트가 자동 배칭됨
function handleClick() {
// 이전: 각각 리렌더링
// React 18: 한 번만 리렌더링
setCount(c => c + 1);
setFlag(f => !f);
}
// 비동기 함수 안에서도 배칭됨
async function handleSubmit() {
await saveToServer();
setCount(c => c + 1); // 한 번만
setFlag(f => !f); // 리렌더링
}
// 배칭 해제가 필요한 경우
import { flushSync } from "react-dom";
flushSync(() => {
setCount(c => c + 1);
}); // 즉시 리렌더링
flushSync(() => {
setFlag(f => !f);
}); // 다시 리렌더링useId - SSR 안전한 ID 생성
import { useId } from "react";
function FormField({ label }) {
const id = useId();
return (
<div>
<label htmlFor={id}>{label}</label>
<input id={id} />
</div>
);
}
// 여러 ID가 필요한 경우
function ComplexForm() {
const id = useId();
return (
<>
<label htmlFor={id + "-name"}>이름</label>
<input id={id + "-name"} />
<label htmlFor={id + "-email"}>이메일</label>
<input id={id + "-email"} />
</>
);
}주의사항
- Strict Mode에서 컴포넌트가 두 번 렌더링됨
- Concurrent 기능은 createRoot 필수
- 클래스 컴포넌트에서는 일부 기능 제한
- IE 지원 중단됨
javascript
| No | 작성일 | Title |
|---|---|---|
| 3384 | 2026. 08. 21. | Node.js API에서 요청 취소를 제대로 처리하는 방법: AbortSignal로 외부 작업 정리하기 |
| 3352 | 2026. 08. 13. | Node.js 응답이 간헐적으로 느릴 때: 이벤트 루프 지연 측정과 CPU 작업 분리 방법 |
| 3320 | 2026. 08. 04. | JavaScript fetch 요청을 안전하게 만드는 방법: timeout·재시도·오류 처리 실전 패턴 |
| 3288 | 2026. 07. 27. | Node.js 서버 무중단 배포를 위한 Graceful Shutdown 구현 가이드 |
| 3257 | 2026. 07. 19. | Node.js 대용량 파일 처리 가이드: 스트림과 backpressure로 메모리 사용량 제어하기 |
| 3232 | 2026. 07. 11. | Node.js 실무형 에러 처리: async/await에서 실패를 일관되게 분류하고 복구 속도 높이기 |
| 3174 | 2026. 07. 02. | Node.js 환경 변수 검증 가이드: process.env를 안전한 설정 객체로 바꾸기 |
| 3123 | 2026. 06. 24. | TypeScript 타입 좁히기 운영 가이드: unknown 입력을 안전한 도메인 객체로 바꾸기 |
| 3065 | 2026. 06. 16. | 브라우저 성능 병목 찾기: PerformanceObserver로 LCP·INP·긴 작업 로그 수집하기 |
| 2978 | 2026. 06. 08. | Node.js fetch 타임아웃과 재시도 설계: 외부 API 장애 전파 줄이기 |