xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

React & Error Boundary & Sentry All In One

React & Error Boundary & Sentry All In One

React, Error Boundary , Sentry, js, error, bug, 埋点, 错误追踪,🙅‍♂️,

https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html

https://reactjs.org/docs/error-boundaries.html

https://reactjs.org/docs/error-boundaries.html#introducing-error-boundaries

React lifecycle methods diagram

image

http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

https://github.com/wojtekmaj/react-lifecycle-methods-diagram

React 16.x

getDerivedStateFromError()

https://reactjs.org/docs/react-component.html#static-getderivedstatefromerror)

componentDidCatch()

https://reactjs.org/docs/react-component.html#componentdidcatch

React & Error Boundary

A JavaScript error in a part of the UI shouldn’t break the whole app.
To solve this problem for React users, React 16 introduces a new concept of an “error boundary”.

UI 的一部分中的 JavaScript 错误不应该破坏整个应用程序。
为了解决 React 用户的这个问题,React 16 引入了“错误边界”的新概念。

A class component becomes an error boundary if it defines either (or both) of the lifecycle methods static getDerivedStateFromError() or componentDidCatch(). Use static getDerivedStateFromError() to render a fallback UI after an error has been thrown. Use componentDidCatch() to log error information.


class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

Error boundaries work like a JavaScript catch {} block, but for components.
Only class components can be error boundaries.
In practice, most of the time you’ll want to declare an error boundary component once and use it throughout your application.

错误边界的工作方式类似于 JavaScript catch {} 块,但适用于组件。
只有类组件可以是错误边界。
在实践中,大多数时候你会希望一次声明一个错误边界组件并在整个应用程序中使用它。

Note that error boundaries only catch errors in the components below them in the tree.
An error boundary can’t catch an error within itself.
If an error boundary fails trying to render the error message, the error will propagate to the closest error boundary above it.
This, too, is similar to how the catch {} block works in JavaScript.

请注意,错误边界仅捕获树中位于它们下方的组件中的错误。
错误边界无法捕获其自身内部的错误。
如果错误边界未能尝试呈现错误消息,则错误将传播到它上方最近的错误边界。
这也类似于 catch {} 块在 JavaScript 中的工作方式。

This change has an important implication.
As of React 16, errors that were not caught by any error boundary will result in unmounting of the whole React component tree.

这一变化具有重要意义。
从 React 16 开始,未被任何错误边界捕获的错误将导致整个 React 组件树的卸载。

This change means that as you migrate to React 16, you will likely uncover existing crashes in your application that have been unnoticed before. Adding error boundaries lets you provide better user experience when something goes wrong.

此更改意味着当您迁移到 React 16 时,您可能会发现您的应用程序中存在以前没有注意到的崩溃。添加错误边界可以让您在出现问题时提供更好的用户体验。

https://reactjs.org/docs/error-boundaries.html

demos

https://codepen.io/xgqfrms/pen/wvEGjrp

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      errorInfo: null,
    };
  }
  componentDidCatch(error, errorInfo) {
    console.log(`error, errorInfo =`, error, errorInfo);
    // Catch errors in any components below and re-render with error message
    this.setState({
      error: error,
      errorInfo: errorInfo,
    });
    // You can also log error messages to an error reporting service here
  }
  render() {
    if (this.state.errorInfo) {
      // Error path
      return (
        <div>
          <h2>❌ Something went wrong.</h2>
          <details style={{ whiteSpace: 'pre-wrap' }}>
            {this.state.error && this.state.error.toString()}
            <br />
            {this.state.errorInfo.componentStack}
          </details>
        </div>
      );
    }
    // Normally, just render children
    return this.props.children;
  }  
}

class BuggyCounter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(({counter}) => ({
      counter: counter + 1
    }));
  }
  render() {
    if (this.state.counter === 3) {
      // Simulate a JS error
      throw new Error('I crashed!');
    }
    return <h1 onClick={this.handleClick}>{this.state.counter}</h1>;
  }
}

function App() {
  return (<>
<p>
  These two counters are <mark>inside the same error boundary.</mark> <br/>
  If one crashes, the error boundary will <mark>replace both of them.</mark>
</p>

    <ErrorBoundary>
        <BuggyCounter />
        <BuggyCounter />
    </ErrorBoundary>

<hr />

<p>
  These two counters are each <mark>inside of their own error boundary.</mark>  <br/>
  So if one crashes, <mark>the other is not affected.</mark>
</p>

    <ErrorBoundary>
        <BuggyCounter />
    </ErrorBoundary>
    <ErrorBoundary>
        <BuggyCounter />
    </ErrorBoundary>
  </>);
}

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(<App />);


https://reactjs.org/docs/error-boundaries.html

React & Sentry

demo


import React, { Component } from 'react';
import { Result, Button, Icon, Typography } from 'antd';
import * as Sentry from '@sentry/browser';

const { Paragraph, Text } = Typography;

class ErrorBoundary extends Component {
  state = { hasError: false };
  componentDidCatch(error) {
    /* eslint-disable */
    console.error(error);
    /* eslint-disable */
    this.setState({ hasError: true });
    Sentry.captureException(error);
  }

  render() {
    if (!this.state.hasError) {
      return this.props.children;
    }
    return (
      <Result
        status='error'
        title='系统出错'
        subTitle='抱歉,请联系系统管理员。'
        extra={
          <Button type='primary' key='reload' onClick={() => window.location.reload()}>
            刷新页面
          </Button>
        }
      >
        <div className='desc'>
          <Paragraph>
            <Text strong style={{ fontSize: 16 }}>
              为了尽快修复问题,完善系统,您可以
            </Text>
          </Paragraph>
          <Paragraph>
            <Icon style={{ color: 'green' }} type='check-circle' /> 钉钉联系前端负责人。
            <a href='dingtalk://dingtalkclient/action/sendmsg?dingtalk_id=xgqfrms'>
              人工智能研发中心-大数据平台部-前端组-凌晨
            </a>
          </Paragraph>
        </div>
      </Result>
    );
  }
}

export default ErrorBoundary;


Sentry 接入

index.js

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

import * as Sentry from '@sentry/browser';

// 初始化sentry
Sentry.init({
  debug: true,
  release: '1.3.0',
  // 关闭 breadcrumbs 的拦截
  integrations(integrations) {
    return integrations.filter(integration => integration.name !== 'Breadcrumbs');
  },
  blacklistUrls: [/http:\/\/localhost:8000*/, /webpack-internal:/],
  whitelistUrls: [/http:\/\/app.xgqfrms.xyz*/],
  dsn: 'https://b1bedbe61c3449b0b8f6e88254e000xyz@websentry.xgqfrms.xyz/131',
});
import React, {
  Component,
} from 'react';

class SentryErrorBoundary extends Component {
    constructor(props) {
        super(props);
        this.state = { error: null, eventId: null };
    }

    componentDidCatch(error, errorInfo) {
      this.setState({ error });
      Sentry.withScope(scope => {
          scope.setExtras(errorInfo);
          const eventId = Sentry.captureException(error);
          this.setState({eventId})
      });
    }

    render() {
        if (this.state.error) {
            //render fallback UI
            return (
              <a onClick={() => Sentry.showReportDialog({ eventId: this.state.eventId })}>Report feedback</a>
            );
        } else {
            //when there's not an error, render children untouched
            return this.props.children;
        }
    }
}

export { SentryErrorBoundary };

export default SentryErrorBoundary;

(🐞 反爬虫测试!打击盗版⚠️)如果你看到这个信息, 说明这是一篇剽窃的文章,请访问 https://www.cnblogs.com/xgqfrms/ 查看原创文章!

refs

https://github.com/xgqfrms/CV/issues/153#issuecomment-1439885863

https://reactjs.org/docs/hooks-faq.html#how-do-lifecycle-methods-correspond-to-hooks

https://github.com/facebook/react/issues/14347

https://stackoverflow.com/questions/48482619/how-can-i-make-use-of-error-boundaries-in-functional-react-components

https://reactgo.com/react-error-boundaries-tutorial/



©xgqfrms 2012-2021

www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!


posted @ 2019-11-13 12:55  xgqfrms  阅读(28)  评论(3编辑  收藏  举报