Error Boundary, Suspense

·2023년 4월 23일
0

개발 지식

목록 보기
60/96
post-thumbnail

React Error Boundary

React Error Boundary는 React 컴포넌트에서 발생한 에러를 처리하기 위한 기능이다. 이를 사용하면 프로그램 전체가 중단되는 것을 방지하고, 대신 컴포넌트의 특정 부분에서 에러 처리를 할 수 있다.

Error Boundary를 적용하기 위해서는 다음과 같은 단계를 따른다.

  1. componentDidCatch(error, info) 메소드를 정의한다.
  2. static getDerivedStateFromError(error) 메소드를 정의한다.
  3. render() 메소드에서 this.state.hasError를 확인하여 에러 처리를 수행한다.

예를 들어, 다음과 같이 Error Boundary 컴포넌트를 만들 수 있다.

import React, { Component } from 'react';

class ErrorBoundary extends Component {
  state = {
    hasError: false
  }

  static getDerivedStateFromError(error) {
    // 에러가 발생했을 때 상태를 업데이트합니다.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // 에러를 로깅합니다.
    console.log(error, info);
  }

  render() {
    // 에러가 발생한 경우 에러 메시지를 출력합니다.
    if (this.state.hasError) {
      return <h1>Oops! Something went wrong.</h1>;
    }

    // 에러가 발생하지 않은 경우 자식 컴포넌트를 렌더링합니다.
    return this.props.children;
  }
}

export default ErrorBoundary;

위 코드에서 ErrorBoundary 컴포넌트는 자식 컴포넌트에서 발생한 에러를 처리한다. getDerivedStateFromError 메소드에서 에러가 발생했을 때 상태를 업데이트하고, componentDidCatch 메소드에서 에러를 로깅하는 것이 가능하다. 마지막으로 render 메소드에서 hasError 상태를 확인하여 에러 처리를 수행한다.

React Suspense

React Suspense는 React 애플리케이션에서 컴포넌트를 분할 렌더링하는 것이 가능하다. 만약 해당 컴포넌트 모듈 자체가 무겁거나, 렌더링 전 API 데이터가 확보가 되어야 하는 경우, 이러한 컴포넌트의 렌더링이 완료될 때까지 다른 컴포넌트를 먼저 나타낼 수 있다. 주로 로딩 스피너를 많이 사용하며, 이를 통해 SPA 의 단점인 초기 TTV 를 어느정도 개선하는 것이 가능하다.

  1. React.lazy()를 사용하여 비동기로 로딩할 컴포넌트를 정의한다.
  2. Suspense 컴포넌트로 감싸서 로딩 중 화면을 표시합한다.
  3. fallback 속성을 사용하여 로딩 중 화면을 정의한다.
import React, { lazy, Suspense } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
}

export default App;

위 코드에서 LazyComponent 컴포넌트는 React.lazy()를 사용하여 비동기로 불러와 진다. Suspense 컴포넌트로 LazyComponent를 감싸면서, 로딩 중 화면으로 <div>Loading...</div>를 정의한다. 이렇게 하면, LazyComponent 컴포넌트가 로딩되는 동안 화면에 로딩 중 화면이 표시된다. 이후 LazyComponent 가 완료되면 로딩 컴포넌트는 언마운트 되고 LazyComponent 가 렌더링 되게 된다.

심화 : 비동기 컴포넌트를 여러개 사용하는 경우

lazy 컴포넌트를 여러개 사용하는 경우에는 Promise.all() 과 같은 형태를 취한다. 즉 모든 비동기 컴포넌트가 모두 렌더링 되기까지 로딩 컴포넌트를 보여준다. 그 밖에도 error boundary 와 함께 결합하여 사용하는 것이 가능하다.

import React, { Suspense } from 'react';
import MyErrorBoundary from './MyErrorBoundary';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

const MyComponent = () => (
  <div>
    <MyErrorBoundary fallback={<div>Error!</div>}>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
);

심화 : react query, swr 와 함께 사용하기

useQuery의 3번째 매개변수는 옵션을 설정하는 것이다. 이 부분의 suspense 값을 true 로 설정하는 경우, ErrorBoundary 와 Suspense 를 함께 적용해서 사용할 수 있다. 이 과정은 useSWR 에서도 그대로 사용할 수 있다.

💡 단, react query, SWR 공식문서에서는 error boundary 및 suspense를 함께 사용하는 것을 권장하지 않는다. 리액트 측에서 업데이트를 통해 향후 바뀔 여지가 있기 때문이다.

기존 useQuery의 경우 로딩 상태나 에러 상태에 따라 따로따로 컴포넌트를 반환해야 하는 것 대비 패칭, 에러, 성공 결과를 한번에 반환하는 것이 가능해서 일단은 유용한듯 하다.

const test = () => {
	const { data } =  useQuery("testQuery", fetchFn, {suspense: true});
	// const { isLoding, error, data } = useQuery("testQuery", fetchFn);
	//if (isLoading) return ...
	//if (error) return ...
	//if (data) return ...
	return (
		<Suspense fallback={<LoadingPage/>}>
			<ErrorBoundary fallback={<ErrorPage />}>
				<TargetWidget data={data} />
			</ErrorBoundary>
		</Suspense>
	)
}
profile
새로운 것에 관심이 많고, 프로젝트 설계 및 최적화를 좋아합니다.

0개의 댓글