Suspense와 ErrorBoundary에 대해 알아보자
React에서 비동기 로딩과 에러 핸들링을 위해 Suspense와 ErrorBoundary는 각각 중요한 역할을 하는 것은 모두가 알고 있는 내용이다.
이 글에서는 두 컴포넌트의 개념을 직접 구현해보는 과정을 통해 내부 구조를 이해하며, 최종적으로 두 컴포넌트의 차이점과 활용 방안을 정리해보고자 한다.
✨ 들어가기
Suspense와 ErrorBoundary는 React에서 각각 비동기 작업의 로딩 상태와 컴포넌트 트리에서 발생하는 오류를 관리하는 데 사용되는 컴포넌트이다.
- Suspense: 비동기 로딩 상태를 처리하기 위해 사용되며, 주로 React.lazy와 함께 활용한다.
즉, Suspense는 컴포넌트를 렌더링하기 전에 로딩 중인 컴포넌트 대신 로딩 UI를 표시하도록 한다. - ErrorBoundary: 자식 컴포넌트에서 발생하는 JavaScript 오류를 캐치하여 전체 앱이 중단되는 것을 방지한다.
즉, ErrorBoundary는 트리의 특정 지점에서 오류를 포착하고, 대체 UI를 표시하는 역할을 한다.
개념으로만 알기에는 부족하니 직접 구현해보는 방향으로 살펴보자
📌 내부 구조를 직접 구현하기
✅ CustomSuspense 구현
Suspense의 기본 원리를 직접 구현해보며, 로딩 상태 관리와 Promise 기반의 비동기 작업을 처리하는 방식을 이해해보자.
import React, { useState, useEffect, ReactNode } from 'react';
interface CustomSuspenseProps {
children: () => Promise<{ default: React.ComponentType<any> }>;
fallback: ReactNode;
}
const CustomSuspense: React.FC<CustomSuspenseProps> = ({ children, fallback }) => {
const [Component, setComponent] = useState<React.ComponentType<any> | null>(null);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
let isMounted = true;
children()
.then((module) => {
if (isMounted) setComponent(() => module.default);
})
.catch((err) => {
if (isMounted) setError(err);
});
return () => {
isMounted = false;
};
}, [children]);
if (error) {
return <div>Error loading component: {error.message}</div>;
}
return Component ? <Component /> : <>{fallback}</>;
};
export default CustomSuspense;
위 코드는 Promise가 완료될 때까지 로딩 UI를 표시하며, 비동기 작업이 완료되면 동적으로 로드된 컴포넌트를 렌더링한다.
✅ CustomErrorBoundary 구현
다음으로, ErrorBoundary의 작동 원리도 직접 구현해보며, 에러 핸들링의 구조를 이해해보자.
import React, { Component, ReactNode } from 'react';
interface ErrorBoundaryProps {
children: ReactNode;
fallback: ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
}
class CustomErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(): ErrorBoundaryState {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error("Error caught by ErrorBoundary:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return this.props.fallback;
}
return this.props.children;
}
}
export default CustomErrorBoundary;
이 코드에서 componentDidCatch 메서드를 통해 자식 컴포넌트의 오류를 감지하고, 에러가 발생하면 hasError 상태를 업데이트하여 대체 UI를 표시하는 구조이다.
🚨두 컴포넌트의 차이점 설명
- 기능 차이:
- Suspense : 비동기 데이터를 로드하는 동안 로딩 상태를 관리하고 표시하는 데 주로 사용
- ErrorBoundary : 런타임 에러가 발생할 때 이를 감지하여 대체 UI를 표시하고, 트리의 특정 지점에서 에러를 차단
- 사용 시점:
- Suspense: 비동기 작업이 필수적인 경우, 특히 React.lazy로 컴포넌트를 동적으로 로드할 때 사용
- ErrorBoundary : JavaScript 에러로 인한 애플리케이션 중단을 방지하고 에러를 특정 지점에서 관리할 필요가 있을 때 사용
- 내부 구조 차이:
- Suspense : Promise 객체를 활용하여 로딩 상태를 관리하고, 비동기 작업이 완료될 때까지 로딩 UI를 표시
- ErrorBoundary : 클래스 컴포넌트의 componentDidCatch 메서드를 통해 자식 컴포넌트에서 발생한 오류를 감지하고, 이를 위한 대체 UI를 제공하는 방식으로 동작
🌈 마무리
React의 Suspense와 ErrorBoundary는 각각 비동기 로딩과 에러 핸들링을 관리하는 데 필수적인 도구이고, 해당 과정을 직접 구현해보며 내부 동작 방식의 차이를 알 수 있었다. 비동기 작업 중 로딩 상태를 관리하고, 자바스크립트 오류로 인한 전체 애플리케이션 중단을 방지할 수 있는 이점이 있기에 적절한 곳에 배치하는 습관을 만들어, 단순히 기능 구현이 아닌 서비스의 성능을 향상시키는 노력을 지속적으로 진행하는 것이 중요할 것 같다.
'WEB > React' 카테고리의 다른 글
중앙화된 인증 처리 시스템 구축하기 (1) | 2024.09.25 |
---|---|
개발자가 만들어가는 어드민 시스템의 UI/UX (0) | 2024.09.24 |
[ React ] 비즈니스 로직 분리하기 (0) | 2023.12.09 |
액션/계산/데이터를 활용한 useMuation 기능 개선 (3) | 2023.12.07 |
React의 패키지 구조와 용어 정리 (0) | 2023.12.03 |