동시성 렌더러가 React의 새로운 심장이 되면서, 팀은 애플리케이션의 안정성을 보장하는 문제에 대해서도 다시 생각하기 시작했다. 특히, 예기치 않은 에러가 발생했을 때 애플리케이션 전체가 멈춰버리는 최악의 상황을 어떻게 막을 것인가 하는 문제였다.
React에는 이미 ‘에러 바운더리(Error Boundary)’라는 개념이 존재했다. 클래스 컴포넌트에 특정 생명주기 메서드(static getDerivedStateFromError
또는 componentDidCatch
)를 구현하여, 자식 컴포넌트 트리에서 발생하는 렌더링 에러를 포착하고 예비 UI를 보여주는 기능이었다.
하지만 이 기능은 몇 가지 한계를 가지고 있었다.
“에러 바운더리는 렌더링 중 발생하는 동기적 에러만 잡을 수 있습니다.”
로렌 탄이 기술 회의에서 지적했다.
“비동기 코드, 예를 들어 setTimeout
이나 이벤트 핸들러 내부에서 발생하는 에러는 포착하지 못합니다. 또한, 자기 자신의 에러는 잡을 수 없고 오직 자식 컴포넌트의 에러만 잡을 수 있다는 점도 한계였죠.”
마치 Suspense
가 데이터 로딩이라는 비동기적인 ‘준비 안 됨’ 상태를 선언적으로 처리하는 것처럼, 팀은 에러 역시 더 포괄적이고 선언적인 방식으로 처리할 방법이 필요하다고 느꼈다.
Suspense
의 성공적인 모델은 에러 처리 방식에도 큰 영감을 주었다.
“Suspense
는 가장 가까운 fallback
을 찾아 렌더링을 위임합니다. 에러 바운더리도 똑같은 원칙을 따라야 합니다.”
이 아이디어를 바탕으로 에러 바운더리의 동작 방식이 확장되고 개선되었다. 이제 에러 바운더리는 더 이상 렌더링 중의 동기 에러에만 국한되지 않았다. 동시성 렌더러의 힘을 빌려, 더 넓은 범위의 에러를 감지하고 처리할 수 있게 되었다.
새로운 에러 처리 메커니즘 하에서, 컴포넌트 트리 일부에서 예기치 않은 에러가 발생하면, React는 Suspense
가 fallback
을 찾는 것과 똑같은 방식으로 가장 가까운 에러 바운더리를 찾아 그곳에 정의된 예비 UI를 보여주었다.
가장 중요한 변화는, 이 과정이 애플리케이션의 다른 부분을 멈추지 않는다는 점이었다.
과거에는 하나의 작은 위젯에서 발생한 렌더링 에러가 전체 페이지를 하얀 화면으로 만들어버리는 경우가 흔했다. 하지만 이제는 아니었다.
- 뉴스피드의 한 게시물 컴포넌트에서 데이터 포맷 문제로 에러가 발생했다.
- React는 그 에러를 감지하고, 해당 게시물을 감싸고 있는 에러 바운더리를 찾아 “이 게시물을 표시할 수 없습니다.”라는 메시지를 보여준다.
- 하지만 페이지의 다른 부분, 즉 헤더, 내비게이션, 그리고 다른 게시물들은 아무런 영향 없이 계속 정상적으로 렌더링되고 상호작용이 가능했다.
에러는 더 이상 전체 시스템을 멈추는 재앙이 아니었다. 그것은 격리되고 통제될 수 있는 국지적인 사고가 되었다.
이러한 변화는 애플리케이션의 견고함(Resilience)을 극적으로 향상시켰다. 개발자는 이제 특정 기능의 실패가 전체 사용자 경험을 망가뜨릴 것을 걱정하지 않고, 더 안정적인 UI를 구축할 수 있게 되었다.
Suspense
가 로딩 상태를 다루는 우아한 방법이었던 것처럼, 개선된 에러 바운더리는 실패 상태를 다루는 우아한 방법이었다. React 19는 성공적인 시나리오뿐만 아니라, 필연적으로 발생하는 실패의 순간까지도 사용자 경험의 일부로 끌어안으며, 한층 더 성숙하고 안정적인 프레임워크로 진화하고 있었다.