React의 Error Boundary는 컴포넌트 렌더링 도중 발생하는 오류를 포착하여 앱이 완전히 중단되지 않도록 돕는 강력한 기능입니다.
하지만 한 가지 중요한 한계가 있습니다 — 비동기 코드에서 발생한 오류는 Error Boundary가 잡을 수 없습니다.
##
왜 Error Boundary는 비동기 에러를 잡지 못할까?
그 이유는 비동기 에러가 렌더링 시점의 콜스택이 모두 비워진 후에 발생하기 때문입니다.
React는 컴포넌트를 렌더링할 때 하나의 연속된 콜스택 안에서 작업을 수행하며, Error Boundary 또한 이 흐름 안에서만 동작합니다.
즉, 동기적인 렌더링 과정 중에 발생한 오류만 감지할 수 있습니다.
class MyComponent extends React.Component {
render() {
throw new Error("렌더링 중 에러 발생!");
}
}
위 코드는 렌더링 시점에 오류가 발생하므로 Error Boundary가 감지할 수 있습니다.
하지만 다음과 같은 코드는 다릅니다.
class MyComponent extends React.Component {
componentDidMount() {
setTimeout(() => {
throw new Error("비동기 에러!");
}, 1000);
}
render() {
return <div>비동기 테스트</div>;
}
}
이 경우, setTimeout
내부에서 발생한 오류는 렌더링이 완료된 후 콜스택이 비워진 뒤에 실행되므로,
Error Boundary는 이를 감지하지 못합니다.
비동기 오류를 처리하는 방법
비동기 오류는 직접적으로 처리해야 합니다. 대표적인 방법은 다음과 같습니다.
1. try...catch
로 감싸기
async function fetchData() {
try {
const res = await fetch("/api/data");
const data = await res.json();
} catch (err) {
console.error("비동기 에러 발생:", err);
}
}
try...catch
를 사용하면 비동기 코드 내에서 발생하는 예외를 직접 잡을 수 있습니다.
2. 상태(state
)로 에러를 관리하기
비동기 에러를 감지하면 setState
로 에러 상태를 저장하고, 이를 렌더링 시점에 반영할 수 있습니다.
function AsyncComponent() {
const [error, setError] = useState(null);
useEffect(() => {
async function run() {
try {
const res = await fetch("/api/data");
if (!res.ok) throw new Error("서버 응답 오류");
} catch (err) {
setError(err);
}
}
run();
}, []);
if (error) {
throw error; // 동기 에러로 재던짐 → Error Boundary가 감지
}
return <div>데이터 로딩 중...</div>;
}
이 방식은 비동기 에러를 Error Boundary
로 전달하기 위해 의도적으로 동기 에러로 변환하는 기법입니다.
정리
구분 | Error Boundary로 감지 가능 여부 | 예시 |
---|---|---|
렌더링 중 에러 | ✅ 가능 | render() 내부에서 throw |
생명주기 메서드 동기 에러 | ✅ 가능 | componentDidMount 내부의 throw |
비동기 함수 내부 에러 | ❌ 불가능 | Promise , setTimeout , fetch 등 |
비동기 → 동기로 변환 | ✅ 가능 | setState 후 throw error |
결론
Error Boundary는 렌더링 시점에 발생하는 동기 오류만 잡을 수 있다.
비동기 에러는 직접 핸들링하거나, 상태를 통해 동기 에러로 전환해야 한다.
이 원리를 이해하면 React 애플리케이션의 안정성을 훨씬 높일 수 있습니다.
'Frontend Development' 카테고리의 다른 글
React 리렌더링(Re-rendering): Trigger → Render → Commit (0) | 2025.10.03 |
---|---|
실무에서 꼭 알아야 할 JWT 저장소 보안 패턴과 공격 탐지 방법 (0) | 2025.09.13 |
Next.js SSR 페이지 풀 페이지 캐싱 (0) | 2025.09.08 |
useEffect에서 setInterval이 상태를 못 따라오는 이유 (stale closure) (0) | 2025.09.07 |
React Error Boundary: 왜 아직도 클래스일까? (0) | 2025.09.07 |