반응형
비동기 데이터를 불러올 때 if (isLoading) return <Spinner />와 같은 명령형 코드를 모든 컴포넌트에 작성하고 계신가요? 리액트 18은 Suspense와 Error Boundary를 통해 비동기 상태와 예외 처리를 UI 구조에서 분리하여 '선언적'으로 다룰 수 있는 환경을 제공합니다.
컴포넌트는 오직 '성공한 화면'에만 집중하고, 로딩과 에러 처리는 부모에게 맡기는 우아한 설계를 배워봅시다.
1. 🎭 Suspense: 로딩 상태를 선언적으로 분리하기
Suspense는 컴포넌트가 아직 렌더링될 준비가 되지 않았을 때(데이터 페칭 중일 때), 대신 보여줄 UI를 정의합니다.
🛠️ 구현 예시
JavaScript
import { Suspense } from 'react';
function ProfilePage() {
return (
<div className="layout">
{/* 데이터가 올 때까지 fallback에 담긴 UI를 보여줍니다. */}
<Suspense fallback={<SkeletonProfile />}>
<UserProfile /> {/* 비동기 데이터를 사용하는 컴포넌트 */}
</Suspense>
<Suspense fallback={<SkeletonPosts />}>
<UserPosts />
</Suspense>
</div>
);
}
- Waterfall 현상 방지: 여러 비동기 작업을 병렬로 처리하면서도 각각의 로딩 시점을 독립적으로 제어할 수 있습니다.
- 사용자 경험(UX): 화면 전체가 멈추는 것이 아니라, 준비된 부분부터 순차적으로 보여주는 '점진적 렌더링'이 가능해집니다.
2. 🛡️ Error Boundary: 에러 발생 시의 '안전망' 구축
컴포넌트 내부에서 에러가 발생했을 때 전체 앱이 화이트아웃(White-out)되는 것을 막아주는 특수 컴포넌트입니다.
🛠️ 구현 예시
JavaScript
// ErrorBoundary는 현재 클래스 컴포넌트로 구현해야 합니다. (혹은 라이브러리 사용)
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return this.props.fallback; // 에러 발생 시 보여줄 UI
}
return this.props.children;
}
}
// 사용 예시
<ErrorBoundary fallback={<ErrorDisplay />}>
<Suspense fallback={<Loader />}>
<MyCriticalComponent />
</Suspense>
</ErrorBoundary>
3. 🧩 선언적 비동기 처리의 핵심: 관심사 분리
이 패턴의 핵심은 컴포넌트의 책임을 나누는 것입니다.
- 비동기 컴포넌트: 데이터가 있다고 가정하고 '성공한 UI'만 작성합니다.
- Suspense: 로딩 시점의 UI(Placeholder)를 결정합니다.
- Error Boundary: 실패했을 때의 복구 UI를 결정합니다.
4. 🚀 실무 팁: react-query와의 시너지
최근 실무에서는 React Query (TanStack Query)와 함께 이 기능을 많이 사용합니다. suspense: true 옵션을 켜면 데이터 페칭 로직이 Suspense와 완벽하게 연동됩니다.
JavaScript
const { data } = useQuery({
queryKey: ['user'],
queryFn: fetchUser,
suspense: true, // 이제 이 훅은 Suspense를 트리거합니다.
});
💡 시니어의 조언: 모든 비동기 컴포넌트를 각각 Suspense로 감쌀 필요는 없습니다. 의미 있는 UI 단위(예: 사이드바, 메인 콘텐츠 영역)로 묶어 최적의 '로딩 시퀀스'를 설계하는 것이 중요합니다.
반응형
'개발 > React' 카테고리의 다른 글
| [고급반] Step 4-1. 테스트와 안정성: Jest와 RTL로 견고한 컴포넌트 만들기 (0) | 2025.12.23 |
|---|---|
| [고급반] Step 3-3. React Server Components(RSC): 클라이언트와 서버의 경계 허물기 (0) | 2025.12.23 |
| [고급반] Step 3-1. Concurrent React: useTransition과 useDeferredValue (0) | 2025.12.23 |
| [고급반] Step 2-3. Headless UI 패턴: 스타일에서 독립된 로직의 힘 (0) | 2025.12.23 |
| [고급반] Step 2-2. 로직 재사용의 기술: Render Props와 HOC (0) | 2025.12.23 |