React 错误边界

学习 React SDK 如何导出一个错误边界组件,该组件利用 React 组件 API。

React SDK 导出了一个错误边界组件,该组件利用 React 组件 API 自动捕获并发送来自 React 组件树内部的 JavaScript 错误到 Sentry。

Copied
import React from "react";
import * as Sentry from "@sentry/react";

<Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}>
  <Example />
</Sentry.ErrorBoundary>;

Sentry 错误边界也作为高阶组件提供。

Copied
import React from "react";
import * as Sentry from "@sentry/react";

Sentry.withErrorBoundary(Example, {
  fallback: <p>an error has occurred</p>,
});

在下面的例子中,当 <Example /> 组件出现错误时,<Sentry.ErrorBoundary> 组件会将有关该错误和组件树的数据发送到 Sentry,打开用户反馈对话框,并渲染备用 UI。

Copied
import React from "react";
import * as Sentry from "@sentry/react";

import { Example } from "../example";

function FallbackComponent() {
  return <div>An error has occurred</div>;
}

const myFallback = <FallbackComponent />;
// Alternatively:
// const myFallback = () => <FallbackComponent />;

class App extends React.Component {
  render() {
    return (
      <Sentry.ErrorBoundary fallback={myFallback} showDialog>
        <Example />
      </Sentry.ErrorBoundary>
    );
  }
}

export default App;

React v17 及以上版本 中,SDK 会自动解析 错误边界 componentStack,并通过 error.cause 将完整的堆栈跟踪附加到事件中。这需要启用 LinkedErrors 集成(默认已启用)。为了获取完整的源代码上下文,我们建议为你的项目设置 source maps

React 错误边界堆栈跟踪

ErrorBoundary 组件暴露了多种 props,可以传递以进行额外配置。没有必填选项,但我们强烈建议你设置一个备用组件。

showDialog (boolean)

如果错误边界捕获到错误时应渲染 Sentry 用户反馈小部件

dialogOptions (Object)

传递给 Sentry 用户反馈小部件的选项。查看所有可能的自定义选项 这里

fallback (React.ReactNode 或 Function)

当错误边界捕获到错误时要渲染的 React 元素。可以是实际的 React 元素(例如 <Fallback />),也可以是返回 React 元素的函数。如果你提供的是函数,Sentry 将使用附加信息和辅助工具调用它(见下面的例子)。

onError (Function)

当错误边界遇到错误时调用的函数。onError 在你想将错误传播到 Redux 等状态管理库中,或检查由于错误可能引发的任何副作用时非常有用。

onMount (Function)

在 ErrorBoundary componentDidMount() 时调用的函数。

onUnmount (Function)

在 ErrorBoundary componentWillUnmount() 时调用的函数。

beforeCapture (Function)

(版本 5.20.0 及以上可用)

在错误发送到 Sentry 之前调用的函数,允许为错误添加额外的标签或上下文。

以下是一个示例,其中使用了 渲染属性方法 的备用 prop,在错误时显示备用 UI。当使用组件通过渲染属性提供的 resetError() API 重置时,备用 UI 将返回到标准组件状态。

Copied
import React from "react";
import * as Sentry from "@sentry/react";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      message: "This is my app",
    };
  }

  render() {
    return (
      <Sentry.ErrorBoundary
        fallback={({ error, componentStack, resetError }) => (
          <React.Fragment>
            <div>You have encountered an error</div>
            <div>{error.toString()}</div>
            <div>{componentStack}</div>
            <button
              onClick={() => {
                this.setState({ message: "This is my app" });
                {
                  /* When resetError() is called it will remove the Fallback component */
                }
                {
                  /* and render the Sentry ErrorBoundary's children in their initial state */
                }
                resetError();
              }}
            >
              Click here to reset!
            </button>
          </React.Fragment>
        )}
      >
        <div>{this.state.message}</div>
        {/* on click, this button sets an Object as a message, not a string. */}
        {/* which will cause an error to occur in the component tree */}
        <button
          onClick={() =>
            this.setState({ message: { text: "Hello World" } })
          }
        >
          Click here to change message!
        </button>
      </Sentry.ErrorBoundary>
    );
  }
}

export default App;

当使用多个错误边界时,我们建议使用 beforeCapture 设置标签/上下文,以便你可以区分错误来自哪个错误边界。在下面的示例中,我们根据错误渲染的路由为错误附加标签。

Copied
import React from "react";
import * as Sentry from "@sentry/react";

function App({ props }) {
  return (
    <React.Fragment>
      <Sentry.ErrorBoundary
        beforeCapture={(scope) => {
          scope.setTag("location", "first");
          scope.setTag("anotherTag", "anotherValue");
        }}
      >
        <Route to="path/to/first" component={First} />
      </Sentry.ErrorBoundary>
      <Sentry.ErrorBoundary
        beforeCapture={(scope) => {
          scope.setTag("location", "second");
        }}
      >
        <Route to="path/to/second" component={Second} />
      </Sentry.ErrorBoundary>
    </React.Fragment>
  );
}

export default App;