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
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://reactgo.com/react-error-boundaries-tutorial/
©xgqfrms 2012-2021
www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!
原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!
本文首发于博客园,作者:xgqfrms,原文链接:https://www.cnblogs.com/xgqfrms/p/11848125.html
未经授权禁止转载,违者必究!