diff --git a/components/alert/ErrorBoundary.tsx b/components/alert/ErrorBoundary.tsx
new file mode 100644
index 0000000000..668ef94156
--- /dev/null
+++ b/components/alert/ErrorBoundary.tsx
@@ -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 ;
+ }
+ return children;
+ }
+}
diff --git a/components/alert/__tests__/__snapshots__/demo.test.js.snap b/components/alert/__tests__/__snapshots__/demo.test.js.snap
index a7a82672eb..a61fee70e9 100644
--- a/components/alert/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/alert/__tests__/__snapshots__/demo.test.js.snap
@@ -1,5 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`renders ./components/alert/demo/error-boundary.md correctly 1`] = `
+
+`;
+
exports[`renders ./components/alert/demo/banner.md correctly 1`] = `
+
+ ReferenceError: NotExisted is not defined
+
+
+
+ in ThrowError
+ in ErrorBoundary (created by WrapperComponent)
+ in WrapperComponent
+
+
+`;
diff --git a/components/alert/__tests__/index.test.js b/components/alert/__tests__/index.test.js
index 9246fe0ef7..8b88773869 100644
--- a/components/alert/__tests__/index.test.js
+++ b/components/alert/__tests__/index.test.js
@@ -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 = () =>
; // eslint-disable-line
+ const wrapper = mount(
+
+
+ ,
+ );
+ // eslint-disable-next-line jest/no-standalone-expect
+ expect(wrapper.render()).toMatchSnapshot();
+ });
});
diff --git a/components/alert/demo/error-boundary.md b/components/alert/demo/error-boundary.md
new file mode 100644
index 0000000000..5da6035733
--- /dev/null
+++ b/components/alert/demo/error-boundary.md
@@ -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 (
+
+ );
+ }
+}
+
+ReactDOM.render(
+
+
+ ,
+ mountNode,
+);
+```
diff --git a/components/alert/index.en-US.md b/components/alert/index.en-US.md
index 7e63f0d0aa..57db85eba4 100644
--- a/components/alert/index.en-US.md
+++ b/components/alert/index.en-US.md
@@ -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 }}` | |
diff --git a/components/alert/index.tsx b/components/alert/index.tsx
index c57e2b6f3e..a3bf3eb9a0 100755
--- a/components/alert/index.tsx
+++ b/components/alert/index.tsx
@@ -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
{
+ static ErrorBoundary = ErrorBoundary;
+
state = {
closing: false,
closed: false,
diff --git a/components/alert/index.zh-CN.md b/components/alert/index.zh-CN.md
index 404d8aaf67..fc3e0acf06 100644
--- a/components/alert/index.zh-CN.md
+++ b/components/alert/index.zh-CN.md
@@ -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 }}` | |
diff --git a/components/alert/style/index.less b/components/alert/style/index.less
index 3e04bd8e4b..0d9e392815 100644
--- a/components/alert/style/index.less
+++ b/components/alert/style/index.less
@@ -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 {
diff --git a/site/theme/template/Content/Demo/index.jsx b/site/theme/template/Content/Demo/index.jsx
index 7f1bbe10ca..556c732e4f 100644
--- a/site/theme/template/Content/Demo/index.jsx
+++ b/site/theme/template/Content/Demo/index.jsx
@@ -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 '-'
diff --git a/site/theme/template/Content/ErrorBoundary.js b/site/theme/template/Content/ErrorBoundary.js
deleted file mode 100644
index 64ffbb2dc2..0000000000
--- a/site/theme/template/Content/ErrorBoundary.js
+++ /dev/null
@@ -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 ;
- }
- return children;
- }
-}