
실제 예제로 알아볼 시간이다.
아래 소스를 보자
interface IModalrrorBoundaryProps {
children: ReactNode;
key?: string;
onReset?: () => void;
}
const ModalErrorBoundary = (props: IModalErrorBoundaryProps) => {
const { children, key = new Date().toISOString(), onReset = () => {} } = props;
const { reset } = useQueryErrorResetBoundary();
const handleOnReset = () => {
reset();
onReset();
};
return (
<ErrorBoundary
resetKeys={[key]}
onReset={handleOnReset}
onError={(error) => {
const description = error instanceof AxiosError ? error?.response?.data?.resultMessage : error.message;
customToast({
message: <CustomToastContent title={'Error'} description={description} />,
status: 'error',
});
}}
fallbackRender={() => <></>}
>
<Suspense fallback={<Spinner />}>{children}</Suspense>
</ErrorBoundary>
);
};
export default ModalErrorBoundary;
위 소스는 공통모달 컴포넌트를 감싸고 있다.
<ModalErrorBoundary>
<ModalComponent />
</ModalErrorBoundary>
요런식으로
그래서 이 모달이 호출될때 에러가 발생하면 ModalErrorBoundary 가 모달과 가장 가까운 Error Boundary 임으로,
이 ErrorBoundary 가 호출되게 된다.
위 ErrorBoundary 를 살펴보면 resetKeys, onReset, onError fallbackRender 가 있다.
위에서 말했듯 Error Boundary 는 컴포넌트의 렌더링 과정에서 발생된 오류만을 처리할 수 있다.
그렇기에, 이벤트 핸들러, 비동기코드, 서버에서 온 에러 는 처리가 안된다.
표로 정리하면 이렇다.
| 오류 유형 | Error Boundary로 처리 가능 여부 | 설명 |
|---|---|---|
| 렌더링 오류 | ✅ 가능 | React 컴포넌트 렌더링 중 발생한 오류 |
| 라이프사이클 오류 | ✅ 가능 | componentDidMount, componentDidUpdate 등에서 발생한 오류 |
| 이벤트 핸들러 오류 | ❌ 불가능 | 이벤트 핸들러는 Error Boundary로 포착되지 않음 |
| 비동기 코드 오류 | ❌ 불가능 | Promise, setTimeout 등에서 발생한 오류 |
| SSR 오류 | ❌ 불가능 | 서버 측 렌더링에서 발생한 오류는 Error Boundary와 무관 |
서버에서 온 에러야 그낭 응답이니까 렌더링 과정이 아니다만 비동기 코드와 이벤트 헨들러는 왜 처리가 안되지? 라는 의문이 들 수도 있다.
이벤트 앤들러는 브라우저 JS 의 이벤트 루프와 연관되어서 비동기 적으로 실행된다.
즉 React 는 이벤트 핸들러를 실행할 때 try-catch 를 내부적으로 사용하지 않고 바로 오류가 브라우저로 전달된다.
function App() {
const handleClick = () => {
throw new Error("Error in event handler!");
};
return <button onClick={handleClick}>Click Me</button>;
}
발생 과정:
onClick 이벤트가 발생 → React의 SyntheticEvent가 이벤트를 감지.
SyntheticEvent가 비동기적으로 이벤트 핸들러(handleClick)를 호출.
이벤트 핸들러에서 오류 발생 → 브라우저 콘솔로 전달.
Error Boundary는 이벤트 핸들러를 감싸고 있지 않기 때문에 오류를 포착하지 못함.
Promise 와 같은 비동기 작업은 react 의 렌더링 작업과는 별도의 실행 컨텍스트에서 작동하게 된다.
즉 react 의 생명주기 와 무관하게 작동되기에 Error Boundary 를 사용할 수 없다.
function App() {
useEffect(() => {
setTimeout(() => {
throw new Error("Error in setTimeout!");
}, 1000);
}, []);
return <div>Hello, world!</div>;
}
발생 과정:
setTimeout은 React의 실행 흐름과 독립적으로 실행됨.
타이머가 만료되면 비동기 콜백이 실행됨.
오류 발생 → 브라우저에게 직접 전달.
Error Boundary는 비동기 흐름을 관리하지 않으므로 오류를 포착하지 못함.
이점 유의해서 Error Boundary 로 더 나은 UX 를 제공해보도록 하자~~
끄읏