⚠️ Add Alert.ErrorBoundary (#19923)

 support ErrorBoundary message and description
This commit is contained in:
偏右 2019-12-11 14:15:45 +08:00 committed by 二货机器人
parent 7b4123258b
commit 05c2f92b69
11 changed files with 164 additions and 24 deletions

View File

@ -0,0 +1,41 @@
import * as React from 'react';
import Alert from '.';
interface ErrorBoundaryProps {
message?: React.ReactNode;
description?: React.ReactNode;
}
export default class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
{
error?: Error | null;
info: {
componentStack?: string;
};
}
> {
state = {
error: undefined,
info: {
componentStack: '',
},
};
componentDidCatch(error: Error | null, info: object) {
this.setState({ error, info });
}
render() {
const { message, description, children } = this.props;
const { error, info } = this.state;
const componentStack = info && info.componentStack ? info.componentStack : null;
const errorMessage = typeof message === 'undefined' ? (error || '').toString() : message;
const errorDescription = typeof description === 'undefined' ? componentStack : description;
if (error) {
// You can render any custom fallback UI
return <Alert type="error" message={errorMessage} description={errorDescription} />;
}
return children;
}
}

View File

@ -1,5 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/alert/demo/error-boundary.md correctly 1`] = `
<button
class="ant-btn ant-btn-danger"
type="button"
>
<span>
Click me to throw a error
</span>
</button>
`;
exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
<div>
<div

View File

@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Alert ErrorBoundary 1`] = `
<div
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon"
data-show="true"
>
<span
class="ant-alert-message"
>
ReferenceError: NotExisted is not defined
</span>
<span
class="ant-alert-description"
>
in ThrowError
in ErrorBoundary (created by WrapperComponent)
in WrapperComponent
</span>
</div>
`;

View File

@ -2,6 +2,8 @@ import React from 'react';
import { mount } from 'enzyme';
import Alert from '..';
const { ErrorBoundary } = Alert;
describe('Alert', () => {
beforeAll(() => {
jest.useFakeTimers();
@ -49,4 +51,16 @@ describe('Alert', () => {
expect(input.getAttribute('role')).toBe('status');
});
});
const testIt = process.env.REACT === '15' ? it.skip : it;
testIt('ErrorBoundary', () => {
const ThrowError = () => <NotExisted />; // eslint-disable-line
const wrapper = mount(
<ErrorBoundary>
<ThrowError />
</ErrorBoundary>,
);
// eslint-disable-next-line jest/no-standalone-expect
expect(wrapper.render()).toMatchSnapshot();
});
});

View File

@ -0,0 +1,51 @@
---
order: 8
title:
zh-CN: ErrorBoundary
en-US: React 错误处理
---
## zh-CN
友好的 [React 错误处理](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html) 包裹组件。
## en-US
ErrorBoundary Component for making error handling easier in [React](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html).
```jsx
import { Button, Alert } from 'antd';
const { ErrorBoundary } = Alert;
class ThrowError extends React.Component {
state = {
error: null,
};
onClick = () => {
this.setState({
error: new Error('An Uncaught Error'),
});
};
render() {
const { error } = this.state;
if (error) {
throw error;
}
return (
<Button type="danger" onClick={this.onClick}>
Click me to throw a error
</Button>
);
}
}
ReactDOM.render(
<ErrorBoundary>
<ThrowError />
</ErrorBoundary>,
mountNode,
);
```

View File

@ -25,3 +25,10 @@ Alert component for feedback.
| showIcon | Whether to show icon | boolean | false, in `banner` mode default is true |
| type | Type of Alert styles, options: `success`, `info`, `warning`, `error` | string | `info`, in `banner` mode default is `warning` |
| onClose | Callback when Alert is closed | (e: MouseEvent) => void | - |
### Alert.ErrorBoundary
| Property | Description | Type | Default | Version |
| ----------- | -------------------------------- | --------- | ------------------- | ------- |
| message | custom error message to show | ReactNode | `{{ error }}` | |
| description | custom error description to show | ReactNode | `{{ error stack }}` | |

View File

@ -16,6 +16,7 @@ import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import getDataOrAriaProps from '../_util/getDataOrAriaProps';
import ErrorBoundary from './ErrorBoundary';
function noop() {}
@ -65,6 +66,8 @@ const iconMapOutlined = {
};
export default class Alert extends React.Component<AlertProps, AlertState> {
static ErrorBoundary = ErrorBoundary;
state = {
closing: false,
closed: false,

View File

@ -26,3 +26,10 @@ title: Alert
| showIcon | 是否显示辅助图标 | boolean | false`banner` 模式下默认值为 true |
| type | 指定警告提示的样式,有四种选择 `success`、`info`、`warning`、`error` | string | `info``banner` 模式下默认值为 `warning` |
| onClose | 关闭时触发的回调函数 | (e: MouseEvent) => void | 无 |
### Alert.ErrorBoundary
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| message | 自定义错误标题,如果未指定会展示原生报错信息 | ReactNode | `{{ error }}` | |
| description | 自定义错误内容,如果未指定会展示报错堆栈 | ReactNode | `{{ error stack }}` | |

View File

@ -63,9 +63,14 @@
&-error {
background-color: @alert-error-bg-color;
border: @border-width-base @border-style-base @alert-error-border-color;
.@{alert-prefix-cls}-icon {
color: @alert-error-icon-color;
}
.@{alert-prefix-cls}-description {
white-space: pre;
}
}
&-close-icon {

View File

@ -5,14 +5,15 @@ import { FormattedMessage, injectIntl } from 'react-intl';
import CopyToClipboard from 'react-copy-to-clipboard';
import classNames from 'classnames';
import LZString from 'lz-string';
import { Tooltip } from 'antd';
import { Tooltip, Alert } from 'antd';
import { SnippetsOutlined, CheckOutlined, ThunderboltOutlined } from '@ant-design/icons';
import stackblitzSdk from '@stackblitz/sdk';
import CodePreview from './CodePreview';
import EditButton from '../EditButton';
import ErrorBoundary from '../ErrorBoundary';
import BrowserFrame from '../../BrowserFrame';
const { ErrorBoundary } = Alert;
function compress(string) {
return LZString.compressToBase64(string)
.replace(/\+/g, '-') // Convert '+' to '-'

View File

@ -1,22 +0,0 @@
import React from 'react';
import { Alert } from 'antd';
export default class ErrorBoundary extends React.Component {
state = {
error: null,
};
componentDidCatch(error, info) {
this.setState({ error, info });
}
render() {
const { children } = this.props;
const { error, info } = this.state;
if (error) {
// You can render any custom fallback UI
return <Alert type="error" message={error.toString()} description={info.componentStack} />;
}
return children;
}
}