에러를 처리하는 다양한 방법
에러에는 다양한 에러가 있다.
Next.js에서 제공하는 error.tsx가 있고, react에서 제공하는 ErrorBoundary가 있다. 이 둘을 각각 어떻게 다르고, 어떻게 에러를 처리할까?
1. error.js
error.js는 react error boundary를 기반으로 만들어졌다. error boundary에서 에러를 던지면, fallback 컴포넌트가 렌더링이 된다. error.js는 layout.js나 template.js에서 던지는 에러를 탐지하지 못한다. layout이나 template에서 잡히는 에러까지 잡고 싶다면, global-error.js를 사용하면 된다.
error.js 코드 살펴보기
// src/components/Error/BaseError.tsx
export interface BaseErrorProps {
error: Error;
reset: () => void;
}
export default function BaseError({ error, reset }: BaseErrorProps) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<Flex align="center" justify="center" className="h-full text-sign-tertiary " direction="column">
<p className="text-30 flex h-48 w-48 items-center justify-center rounded-full bg-sign-caption text-white">
X
</p>
<Spacing size={20} />
<p className="text-center text-subtitle-1">
오류가 발생했습니다.
<br />
잠시 후 다시 시도해 주세요.
</p>
<button
className="bg-grey-200 text-13 mt-16 block rounded-lg px-12 py-8 font-bold"
onClick={reset}
>
다시 불러오기
</button>
</Flex>
);
}
error, reset을 props로 받아서 에러 메시지를 보여주고, 페이지를 reload할 수 있는 버튼을 추가할 수 있다.
또한, 사용자가 원한다면 다시 로그인을 할 수 있도록 로그아웃 버튼도 추가했다.
// src/app/error.tsx
export default function Error({ error, reset }: ErrorProps) {
return (
<>
<BaseError error={error} reset={reset} />
<Footer lng="ko" />
</>
);
}
페이지를 이동할 수 있는 Footer를 추가하여 사용자에게 다른 페이지로 이동할 수 있는 선택권도 줄 수 있다.
2. ErrorBoundary
Error Boundary는 하위 컴포넌트 트리의 어디에서든 Javascript 에러를 기록하여 깨진 컴포넌트 트리 대신 fallback UI를 보여주는 React 컴포넌트이다.
그렇다. 위의 Next.js에서 제공하는 error.js와 매우 유사하다.
error.js를 사용하면 ErrorBoundary는 사용하지 않아도 될까?
error.js는 애플리케이션 전반에 걸친 에러 핸들링 로직을 구현할 수 있다. ErrorBoundary는 컴포넌트 트리에서 Javascript 에러를 포착하고, 로그를 기록하며, 충돌한 컴포넌트 트리 대신 대체 UI를 렌더링하는데 사용된다.
이 둘은 서로 배타적이지 않다. 실제로, 효과적인 에러 관리를 위해서는 두 방법을 모두 함께 사용하는 것이 좋다. error.js를 통해 애플리케이션 전반의 에러를 관리하고, ErrorBoundary를 사용하여 특정 컴포넌트 또는 컴포넌트 그룹에서 발생하는 UI에러를 우아하게 처리할 수 있다.
- ErrorBoundary는 컴포넌트 단위로 작성이 가능하다.
- UI 렌더링 중 잘못된 데이터 형식, 렌더링 중의 오류 등을 처리하는 데 적합하다.
- error.js는 페이지 단위로 작성이 가능하다
- 다른 유형의 에러, 예를 들어 API 호출 실패, 네트워크 문제 등을 다루는데 적합하다
ErrorBoundary의 한계
ErrorBoundary가 포착하지 못하는 에러가 있다.
- 이벤트 핸들러 내부 에러
- 이벤트 핸들러는 render메서드 및 생명주기 메서드와 달리 렌더링 중에 발생하지 않는다.
- 이러한 경우, try/catch문을 사용해야 한다.
- 비동기 코드 e.g. setTimeout, requestAnimationFrame
- 서버 사이드 렌더링
- 오류 경계 자체에서 발생한 오류(하위가 아닌)
정말로 ErrorBoundary가 필요할까?
정말로 ErrorBoundary가 필요할까 고민을 했다.
export default function GroupingPage({ params: { lng } }: GroupingPageProps) {
throw new Error('test');
return <div></div>
}
위와 같이 throw new Error를 했을 때도 error.js가 에러 페이지를 던졌다. Next.js에서 제공하는 error.js의 에러페이지가 렌더링이 되었다.
이 쯤 되면 드는 생각이, error.js가 모든 ErrorBoundary의 기능을 지원하는 게 아닐까?

그렇다. error.js는 루트 뿐 아니라 각 페이지 폴더 안에도 넣어서 페이지별 처리를 할 수 있지만, 컴포넌트 단위로 처리를 하지 못한다는 것이다. 그래서, 컴포넌트 단위로 에러 처리를 하고 싶다면 ErrorBoundary, 페이지 단위로 처리하고 싶다면 error.js를 사용하면 되겠다는 결론을 내렸다.
결론
error.js와 Errorboundary의 목적이 다르다. error.js는 페이지 단위로 에러 처리를 할 때, ErrorBoundary는 컴포넌트 단위로 에러 처리를 할 때 사용하는 것이다. 앞으로 이러한 둘의 차이를 생각하면서 개발을 해야겠다.
업로드 PR
https://github.com/gloddy-dev/gloddy-client/pull/576