生产就绪的 React 错误边界:优雅失败的模式

发布: (2026年4月7日 GMT+8 16:52)
4 分钟阅读
原文: Dev.to

Source: Dev.to

未处理的渲染错误会导致整个 React 树崩溃。错误边界可以限制损害。以下是在生产环境中有效使用它们的方法。

问题

// If UserCard throws, the entire page goes blank
function Dashboard() {
  return (
    <>
      {/* if this throws, everything dies */}
    </>
  )
}

基本错误边界

import React, { Component, ReactNode } from 'react'

interface Props {
  children: ReactNode
  fallback?: ReactNode
}

interface State {
  hasError: boolean
  error: Error | null
}

class ErrorBoundary extends Component<Props, State> {
  state: State = { hasError: false, error: null }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error }
  }

  componentDidCatch(error: Error, info: React.ErrorInfo) {
    console.error('ErrorBoundary caught:', error, info.componentStack)
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback ?? <>Something went wrong</>
    }
    return this.props.children
  }
}

使用 react-error-boundary

不要自己实现——使用经过实战检验的库:

npm install react-error-boundary
import { ErrorBoundary, FallbackProps } from 'react-error-boundary'

function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
  return (
    <>
      <h2>Something went wrong</h2>
      <p>{error.message}</p>
      <button onClick={resetErrorBoundary}>Try again</button>
    </>
  )
}

function Dashboard() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      {/* Your dashboard content */}
    </ErrorBoundary>
  )
}

粒度边界

将独立的部分进行包装——其中一个部分的失败不应影响其他部分:

function Dashboard() {
  return (
    <>
      <ErrorBoundary FallbackComponent={WidgetError}>
        {/* Widget A */}
      </ErrorBoundary>

      <ErrorBoundary FallbackComponent={WidgetError}>
        {/* Widget B */}
      </ErrorBoundary>

      <ErrorBoundary FallbackComponent={WidgetError}>
        {/* Widget C */}
      </ErrorBoundary>
    </>
  )
}

function WidgetError({ error, resetErrorBoundary }: FallbackProps) {
  return (
    <>
      <p>Failed to load widget</p>
      <button onClick={resetErrorBoundary}>Retry</button>
    </>
  )
}

将错误记录到您的错误监控服务

import * as Sentry from '@sentry/nextjs'

function onError(error: Error, info: { componentStack: string }) {
  Sentry.captureException(error, {
    extra: { componentStack: info.componentStack },
  })
}

路由更改时重置

import { useLocation } from 'react-router-dom'
import { ErrorBoundary } from 'react-error-boundary'

function App() {
  const location = useLocation()

  return (
    <ErrorBoundary
      onReset={() => {
        // Reset logic when the route changes
      }}
      resetKeys={[location.pathname]}
    >
      {/* Your app routes */}
    </ErrorBoundary>
  )
}

什么错误边界 不会 捕获

  • 事件处理函数中的错误(在处理函数内部使用 try/catch
  • 异步代码中的错误(使用 try/catch 并结合组件状态处理)
  • 服务端渲染期间的错误
  • 在边界组件本身内部抛出的错误
// This WON’T be caught by an error boundary:
function Button() {
  const handleClick = async () => {
    try {
      await submitForm() // async error — handle here
    } catch (err) {
      setError(err.message)
    }
  }
  return <button onClick={handleClick}>Submit</button>
}

路由级别边界(Route‑Level Boundaries)在 Next.js 中

在 Next.js App Router 中,使用 error.tsx

// app/dashboard/error.tsx
'use client'

export default function DashboardError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <>
      <h2>Dashboard failed to load</h2>
      <button onClick={reset}>Try again</button>
    </>
  )
}

此文件充当整个 /dashboard 路由段的内置错误边界。

生产检查清单

  • Next.js 中的路由级 error.tsx 文件
  • 对独立小部件进行细粒度边界划分
  • 错误报告已接入(Sentry / LogRocket)
  • 有意义的回退 UI(不仅仅是白屏)
  • 重置按钮,让用户能够恢复
  • 事件处理程序中的异步错误处理

AI SaaS Starter Kit 已集成 Sentry,配置了路由级错误边界,并预先接入所有生产环境错误处理模式。一次性 $99 — 克隆后即可发布。

0 浏览
Back to Blog

相关文章

阅读更多 »