Skip to content

Commit 4bf39ea

Browse files
JackWang032jialan
andauthored
feat: refactor errorBoundary (#308)
* feat: refactor errorBoundary * feat: update ErrorBoundaryState interface name --------- Co-authored-by: jialan <[email protected]>
1 parent 31f9095 commit 4bf39ea

File tree

8 files changed

+123
-81
lines changed

8 files changed

+123
-81
lines changed

src/errorBoundary/__tests__/errorBoundary.test.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,24 @@ describe('test ErrorBoundary', () => {
3737
});
3838
// 测试发生错误情况
3939
test('should render error when some error occur', () => {
40-
const wrapper = render(<ErrorBoundary>{<ThrowError />}</ErrorBoundary>);
40+
const errorFn = jest.fn();
41+
const wrapper = render(
42+
<ErrorBoundary onError={(err) => errorFn(err)}>
43+
<ThrowError />
44+
</ErrorBoundary>
45+
);
4146
const element = wrapper.getByText('刷新');
4247
expect(element).toBeInTheDocument();
4348
expect(console.error).toHaveBeenCalledTimes(2);
49+
expect(errorFn.mock.calls[0][0].message).toEqual('测试error, 请忽略');
50+
});
51+
52+
test('should render custom error page', () => {
53+
const wrapper = render(
54+
<ErrorBoundary errorPage={<div>这是自定义错误页面</div>}>
55+
<ThrowError />
56+
</ErrorBoundary>
57+
);
58+
expect(wrapper.getByText('这是自定义错误页面')).toBeInTheDocument();
4459
});
4560
});

src/errorBoundary/demos/basic.tsx

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,39 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { ErrorBoundary } from 'dt-react-component';
3+
import { message } from 'antd';
34

4-
class ThrowError extends React.Component {
5-
state = {
6-
count: 0,
7-
};
8-
render() {
9-
const { count } = this.state;
10-
if (count % 2) throw new Error('test error');
11-
else {
12-
return (
13-
<div
14-
style={{
15-
display: 'flex',
16-
flexDirection: 'column',
17-
justifyContent: 'center',
18-
alignItems: 'center',
19-
}}
20-
>
21-
<button
22-
style={{
23-
border: 'none',
24-
backgroundColor: '#1890ff',
25-
cursor: 'pointer',
26-
height: '32px',
27-
borderRadius: '4px',
28-
}}
29-
onClick={() => this.setState({ count: count + 1 })}
30-
>
31-
catch error
32-
</button>
33-
<h2>hello, dt-react-component</h2>
34-
</div>
35-
);
36-
}
37-
}
38-
}
5+
const ThrowError = () => {
6+
const [count, setCount] = useState(0);
7+
if (count % 2) throw new Error('test error');
8+
return (
9+
<div
10+
style={{
11+
display: 'flex',
12+
flexDirection: 'column',
13+
justifyContent: 'center',
14+
alignItems: 'center',
15+
}}
16+
>
17+
<button
18+
style={{
19+
border: 'none',
20+
backgroundColor: '#1890ff',
21+
cursor: 'pointer',
22+
height: '32px',
23+
borderRadius: '4px',
24+
}}
25+
onClick={() => setCount((count) => count + 1)}
26+
>
27+
触发异常
28+
</button>
29+
<h2>hello, dt-react-component</h2>
30+
</div>
31+
);
32+
};
3933

4034
export default () => {
4135
return (
42-
<ErrorBoundary>
36+
<ErrorBoundary onError={(err) => message.error('捕获到错误:' + err.message)}>
4337
<ThrowError />
4438
</ErrorBoundary>
4539
);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React, { useState } from 'react';
2+
import { ErrorBoundary } from 'dt-react-component';
3+
import { message } from 'antd';
4+
5+
const ThrowError = () => {
6+
const [count, setCount] = useState(0);
7+
if (count % 2) throw new Error('test error');
8+
return (
9+
<div
10+
style={{
11+
display: 'flex',
12+
flexDirection: 'column',
13+
justifyContent: 'center',
14+
alignItems: 'center',
15+
}}
16+
>
17+
<button
18+
style={{
19+
border: 'none',
20+
backgroundColor: '#1890ff',
21+
cursor: 'pointer',
22+
height: '32px',
23+
borderRadius: '4px',
24+
}}
25+
onClick={() => setCount((count) => count + 1)}
26+
>
27+
触发异常
28+
</button>
29+
<h2>hello, dt-react-component</h2>
30+
</div>
31+
);
32+
};
33+
34+
const ErrorPage = () => {
35+
return (
36+
<div style={{ textAlign: 'center' }}>
37+
<h2>这是自定义捕获异常页面</h2>
38+
</div>
39+
);
40+
};
41+
42+
export default () => {
43+
return (
44+
<ErrorBoundary
45+
onError={(err) => message.error('捕获到错误:' + err.message)}
46+
errorPage={<ErrorPage />}
47+
>
48+
<ThrowError />
49+
</ErrorBoundary>
50+
);
51+
};

src/errorBoundary/index.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: ErrorBoundary 错误边界
33
group: 组件
44
toc: content
55
demo:
6-
cols: 2
6+
cols: 1
77
---
88

99
# ErrorBoundary 错误边界
@@ -14,10 +14,13 @@ demo:
1414

1515
## 示例
1616

17-
<code src="./demos/basic.tsx" iframe="true"></code>
17+
<code src="./demos/basic.tsx" iframe="true">基本使用</code>
18+
<code src="./demos/customErrorPage.tsx" iframe="true" description='可以自定义渲染错误处理页面'>自定义错误页面</code>
1819

1920
## API
2021

21-
| 参数 | 说明 | 类型 | 默认值 |
22-
| -------- | ------ | ----------------- | ------ |
23-
| children | 子组件 | `React.ReactNode` | - |
22+
| 参数 | 说明 | 类型 | 默认值 |
23+
| --------- | ------------------ | ------------------------ | --------------- |
24+
| children | 子组件 | `React.ReactNode` | - |
25+
| errorPage | 自定义错误展示页面 | `React.ReactNode` | `<LoadError />` |
26+
| onError | 发生错误捕获时触发 | `(error: Error) => void` | - |

src/errorBoundary/index.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,39 @@
11
import React from 'react';
2-
import LoadError from '../loadError';
2+
import LoadError from './loadError';
33

4-
interface ErrorBoundaryProps {
4+
interface IErrorBoundaryProps {
55
children?: React.ReactNode;
6+
errorPage?: React.ReactNode;
7+
onError?: (error: Error) => void;
68
}
79

8-
interface ErrorBoundaryStates {
10+
interface IErrorBoundaryState {
911
hasError: boolean;
1012
}
1113
export default class ErrorBoundary extends React.Component<
12-
ErrorBoundaryProps,
13-
ErrorBoundaryStates
14+
IErrorBoundaryProps,
15+
IErrorBoundaryState
1416
> {
1517
state = { hasError: false };
1618
static getDerivedStateFromError(_error: any) {
1719
// Update state so the next render will show the fallback UI.
1820
return { hasError: true };
1921
}
2022

21-
componentDidCatch(error: any, errorInfo: any) {
23+
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
2224
this.setState({ hasError: true });
25+
this.props.onError?.(error);
2326
console.log(error);
2427
console.log(errorInfo);
2528
}
2629

2730
render() {
28-
if (this.state.hasError) {
29-
return <LoadError />;
31+
const { children, errorPage = <LoadError /> } = this.props;
32+
const { hasError } = this.state;
33+
34+
if (hasError) {
35+
return errorPage;
3036
}
31-
return this.props.children;
37+
return children;
3238
}
3339
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22

33
const LoadError: React.FC = function () {
44
return (
5-
<div className="error" data-testid="test-error">
5+
<div className="dtc-error" data-testid="test-error">
66
<div>
77

88
<h2 style={{ textAlign: 'center' }} data-testid="test-error">

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export { default as Form } from './form';
1111
export { default as Fullscreen } from './fullscreen';
1212
export { default as GlobalLoading } from './globalLoading';
1313
export { default as KeyEventListener } from './keyEventListener';
14-
export { default as LoadError } from './loadError';
14+
export { default as LoadError } from './errorBoundary/loadError';
1515
export { default as MarkdownRender } from './markdownRender';
1616
export { default as ModalWithForm } from './modalWithForm';
1717
export { default as MultiSearchInput } from './multiSearchInput';

src/loadError/__tests__/loadError.test.tsx

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)