React 18은 단순한 업데이트가 아닙니다. Concurrent Features의 도입으로 React 개발 패러다임이 완전히 바뀌었습니다. 이 가이드에서는 React 18의 핵심 기능들을 실제 코드와 함께 살펴보겠습니다.
1. React 18의 핵심 변화
React 18은 사용자 경험을 크게 개선하는 여러 혁신적 기능을 도입했습니다. 가장 주목할 만한 변화는 동시성(Concurrency) 지원입니다.
💡 React 18 주요 특징
- Automatic Batching - 모든 업데이트 자동 배칭
- Concurrent Features - 논블로킹 렌더링
- Suspense 개선 - 서버사이드 지원
- 새로운 Hooks - useTransition, useDeferredValue
// React 18 설치 및 설정
npm install react@18 react-dom@18
// 새로운 createRoot API 사용
import { createRoot } from 'react-dom/client';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);
2. Automatic Batching - 성능의 혁신
React 18의 가장 눈에 띄는 개선사항 중 하나는 Automatic Batching입니다. 이제 모든 상태 업데이트가 자동으로 배칭됩니다.
// React 17 vs React 18 비교
function handleClick() {
// React 17: Promise, setTimeout에서 배칭 안됨
fetch('/api/data').then(() => {
setCount(c => c + 1); // 리렌더링 발생
setFlag(f => !f); // 리렌더링 발생
});
}
function handleClickReact18() {
// React 18: 모든 업데이트 자동 배칭
fetch('/api/data').then(() => {
setCount(c => c + 1); // 배칭됨
setFlag(f => !f); // 배칭됨 - 한 번만 리렌더링
});
}
// 배칭을 원하지 않는 경우
import { flushSync } from 'react-dom';
function handleNoAutoBatch() {
flushSync(() => {
setCount(c => c + 1);
});
// DOM이 업데이트됨
flushSync(() => {
setFlag(f => !f);
});
// DOM이 다시 업데이트됨
}
⚡ 성능 개선 효과
Automatic Batching으로 불필요한 리렌더링이 50% 감소하여 앱 성능이 크게 향상됩니다.
3. Concurrent Features - 논블로킹 렌더링
React 18의 핵심인 Concurrent Features는 UI 반응성을 크게 개선합니다. 사용자 입력에 대한 즉각적인 반응이 가능해집니다.
useTransition Hook
import { useState, useTransition } from 'react';
function SearchApp() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
const handleSearch = (value) => {
setQuery(value); // 긴급 업데이트 - 즉시 반영
startTransition(() => {
// 비긴급 업데이트 - 중단 가능
setResults(heavySearchFunction(value));
});
};
return (
<div>
<input
value={query}
onChange={e => handleSearch(e.target.value)}
placeholder="검색어를 입력하세요..."
/>
{isPending && <div>검색 중...</div>}
<SearchResults results={results} />
</div>
);
}
useDeferredValue Hook
import { useState, useDeferredValue, memo } from 'react';
function App() {
const [text, setText] = useState('');
const deferredText = useDeferredValue(text);
return (
<>
<input
value={text}
onChange={e => setText(e.target.value)}
placeholder="실시간 검색..."
/>
<SlowList text={deferredText} />
</>
);
}
const SlowList = memo(({ text }) => {
// 무거운 렌더링 작업
const items = useMemo(() => {
return generateLargeList(text); // 비용이 큰 연산
}, [text]);
return <ul>{items}</ul>;
});
🎯 실무 활용 시나리오
검색창에서 즉각적인 입력 반응을 유지하면서 검색 결과는 지연 처리하여 사용자 경험을 크게 개선할 수 있습니다.
4. Suspense 개선사항
React 18에서 Suspense가 크게 개선되어 서버사이드 렌더링과 더 나은 에러 처리를 지원합니다.
// React 18 Suspense with SSR
function App() {
return (
<div>
<Header />
<Suspense fallback={<LoadingSpinner />}>
<MainContent />
<Suspense fallback={<SidebarSkeleton />}>
<Sidebar />
</Suspense>
</Suspense>
<Footer />
</div>
);
}
// 중첩된 Suspense 경계
function MainContent() {
return (
<div>
<h1>메인 콘텐츠</h1>
<Suspense fallback={<CommentsSkeleton />}>
<Comments />
</Suspense>
</div>
);
}
5. 실무 최적화 패턴
React 18의 새로운 기능들을 실무에서 효과적으로 활용하는 패턴들을 소개합니다.
우선순위 기반 렌더링
function TodoApp() {
const [todos, setTodos] = useState([]);
const [filter, setFilter] = useState('all');
const [isPending, startTransition] = useTransition();
const urgentUpdate = (newTodo) => {
// 사용자 입력은 즉시 반영
setTodos(prev => [...prev, newTodo]);
};
const nonUrgentUpdate = (newFilter) => {
// 필터링은 지연 가능한 업데이트
startTransition(() => {
setFilter(newFilter);
});
};
return (
<div>
<AddTodo onAdd={urgentUpdate} />
<FilterButtons
onFilterChange={nonUrgentUpdate}
isPending={isPending}
/>
<TodoList todos={todos} filter={filter} />
</div>
);
}
메모리 최적화
// React 18 + TypeScript 최적화 패턴
import { memo, useMemo, useCallback, startTransition } from 'react';
interface Props {
items: Item[];
onItemClick: (id: string) => void;
}
const OptimizedList = memo<Props>(({ items, onItemClick }) => {
const sortedItems = useMemo(() => {
return items.sort((a, b) => a.priority - b.priority);
}, [items]);
const handleClick = useCallback((id: string) => {
startTransition(() => {
onItemClick(id);
});
}, [onItemClick]);
return (
<ul>
{sortedItems.map(item => (
<ListItem
key={item.id}
item={item}
onClick={handleClick}
/>
))}
</ul>
);
});
6. 마이그레이션 가이드
기존 React 17 프로젝트를 React 18로 안전하게 업그레이드하는 방법을 알아보겠습니다.
# 1. React 18 설치
npm install react@18 react-dom@18
npm install --save-dev @types/react@18 @types/react-dom@18
# 2. TypeScript 설정 업데이트 (tsconfig.json)
{
"compilerOptions": {
"types": ["react/next", "react-dom/next"]
}
}
// 3. 점진적 마이그레이션
// 기존 앱은 그대로 동작
ReactDOM.render(<App />, document.getElementById('root'));
// 새로운 기능이 필요한 곳만 createRoot 사용
import { createRoot } from 'react-dom/client';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);
⚠️ 마이그레이션 주의사항
React 18은 하위 호환성을 보장하므로 기존 코드는 수정 없이 동작합니다. 새로운 기능만 선택적으로 적용하세요.
마무리
React 18은 웹 개발의 새로운 지평을 열었습니다. Concurrent Features로 인한 성능 향상과 사용자 경험 개선은 모든 React 개발자가 주목해야 할 변화입니다.
🚀 React 18 도입 효과
- 렌더링 성능 50% 향상
- 사용자 상호작용 응답성 개선
- 메모리 사용량 최적화
- 개발 생산성 증대
지금 바로 React 18로 업그레이드하여 차세대 웹 개발의 혜택을 누려보세요!