mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:58:07 +08:00
Merge pull request #8844 from wibetter/master
fix(amis): StaticHoc改用componentDidCatch拦截渲染异常
This commit is contained in:
commit
b326802b1c
58
packages/amis-core/src/components/ErrorBoundary.tsx
Normal file
58
packages/amis-core/src/components/ErrorBoundary.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file ErrorBoundary
|
||||
* @description 捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误
|
||||
* @author wibetter
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
interface ErrorBoundaryProps {
|
||||
// 自定义错误信息,控制台输出
|
||||
customErrorMsg?: string;
|
||||
fallback?: () => void;
|
||||
children: any;
|
||||
}
|
||||
|
||||
interface ErrorBoundaryStates {
|
||||
hasError: boolean;
|
||||
}
|
||||
|
||||
export default class ErrorBoundary extends React.Component<
|
||||
ErrorBoundaryProps,
|
||||
ErrorBoundaryStates
|
||||
> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {hasError: false};
|
||||
}
|
||||
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
const {customErrorMsg} = this.props;
|
||||
if (customErrorMsg) {
|
||||
console.warn(customErrorMsg);
|
||||
}
|
||||
|
||||
console.warn('错误对象:', error);
|
||||
console.warn('错误信息:', errorInfo);
|
||||
this.setState({
|
||||
hasError: true
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {fallback} = this.props;
|
||||
if (this.state.hasError) {
|
||||
if (fallback) {
|
||||
return fallback();
|
||||
}
|
||||
|
||||
// 默认渲染错误信息
|
||||
return (
|
||||
<div className="renderer-error-boundary">
|
||||
渲染发生错误,详细错误信息请查看控制台输出。
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
@ -96,6 +96,7 @@ import type {FilterContext} from 'amis-formula';
|
||||
import LazyComponent from './components/LazyComponent';
|
||||
import Overlay from './components/Overlay';
|
||||
import PopOver from './components/PopOver';
|
||||
import ErrorBoundary from './components/ErrorBoundary';
|
||||
import {FormRenderer} from './renderers/Form';
|
||||
import type {FormHorizontal, FormSchemaBase} from './renderers/Form';
|
||||
import {
|
||||
@ -182,6 +183,7 @@ export {
|
||||
LazyComponent,
|
||||
Overlay,
|
||||
PopOver,
|
||||
ErrorBoundary,
|
||||
addSchemaFilter,
|
||||
OptionsControlProps,
|
||||
FormOptionsControl,
|
||||
|
@ -801,14 +801,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.ae-Editor-renderer-error {
|
||||
padding: 5px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-size: 14px;
|
||||
color: #cf1322;
|
||||
border: 1px dashed #cf1322;
|
||||
}
|
||||
|
||||
.ae-Editor-tip {
|
||||
user-select: none;
|
||||
max-width: 100px;
|
||||
|
@ -23,7 +23,8 @@ import {
|
||||
JSONUpdate,
|
||||
getFixDialogType
|
||||
} from '../util';
|
||||
import {createObject, createObjectFromChain} from 'amis-core';
|
||||
import {createObjectFromChain} from 'amis-core';
|
||||
import {ErrorBoundary} from 'amis-core';
|
||||
import {CommonConfigWrapper} from './CommonConfigWrapper';
|
||||
import type {Schema} from 'amis';
|
||||
import type {DataScope} from 'amis-core';
|
||||
@ -40,14 +41,11 @@ export function makeWrapper(
|
||||
type Props = RendererProps & {
|
||||
$$id: string;
|
||||
};
|
||||
type States = {
|
||||
hasError: boolean;
|
||||
};
|
||||
const store = manager.store;
|
||||
const renderer = rendererConfig.component;
|
||||
|
||||
@observer
|
||||
class Wrapper extends React.Component<Props, States> {
|
||||
class Wrapper extends React.Component<Props> {
|
||||
static displayName = renderer.displayName;
|
||||
static propsList = ((renderer && renderer.propsList) || []).concat([
|
||||
'$$id'
|
||||
@ -57,11 +55,6 @@ export function makeWrapper(
|
||||
editorNode?: EditorNodeType;
|
||||
scopeId?: string;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {hasError: false};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
const parent: EditorNodeType = (this.context as any) || store.root;
|
||||
if (!info.id) {
|
||||
@ -133,16 +126,6 @@ export function makeWrapper(
|
||||
}
|
||||
}
|
||||
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
console.warn(`${info.name}(${info.id})渲染发生错误:`);
|
||||
console.warn('当前渲染器信息:', info);
|
||||
console.warn('错误对象:', error);
|
||||
console.warn('错误信息:', errorInfo);
|
||||
this.setState({
|
||||
hasError: true
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.editorNode && isAlive(this.editorNode)) {
|
||||
const parent: EditorNodeType = (this.context as any) || store.root;
|
||||
@ -186,14 +169,6 @@ export function makeWrapper(
|
||||
render() {
|
||||
const {$$id, ...rest} = this.props;
|
||||
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div className="ae-Editor-renderer-error">
|
||||
{info.name}({info.id})渲染发生错误,详细错误信息请查看控制台输出。
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* 根据渲染器信息决定时 NodeWrapper 包裹还是 ContainerWrapper 包裹。
|
||||
* NodeWrapper 主要完成 dom 节点的标记(即:添加 data-editor-id 属性)。
|
||||
@ -207,18 +182,31 @@ export function makeWrapper(
|
||||
: info.regions
|
||||
? ContainerWrapper
|
||||
: NodeWrapper; /*)*/
|
||||
|
||||
return (
|
||||
<EditorNodeContext.Provider
|
||||
value={this.editorNode || (this.context as any)}
|
||||
>
|
||||
<Wrapper
|
||||
{...rest}
|
||||
render={this.renderChild}
|
||||
$$editor={info}
|
||||
$$node={this.editorNode}
|
||||
ref={this.wrapperRef}
|
||||
/>
|
||||
<ErrorBoundary
|
||||
customErrorMsg={`拦截到${
|
||||
info.type
|
||||
}渲染错误,当前组件信息: ${JSON.stringify(this.props.$schema)}`}
|
||||
fallback={() => {
|
||||
return (
|
||||
<div className="renderer-error-boundary">
|
||||
{info?.type}
|
||||
渲染发生错误,详细错误信息请查看控制台输出。
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Wrapper
|
||||
{...rest}
|
||||
render={this.renderChild}
|
||||
$$editor={info}
|
||||
$$node={this.editorNode}
|
||||
ref={this.wrapperRef}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</EditorNodeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -9,3 +9,11 @@
|
||||
.visibility-sensor {
|
||||
min-height: 5px;
|
||||
}
|
||||
|
||||
.renderer-error-boundary {
|
||||
padding: 5px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-size: 14px;
|
||||
color: #cf1322;
|
||||
border: 1px dashed #cf1322;
|
||||
}
|
||||
|
@ -67,7 +67,6 @@
|
||||
"qrcode.react": "^3.1.0",
|
||||
"react-cropper": "^2.1.8",
|
||||
"react-dropzone": "^11.4.2",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-intersection-observer": "9.5.2",
|
||||
"react-json-view": "1.21.3",
|
||||
"react-transition-group": "4.4.2",
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import toString from 'lodash/toString';
|
||||
import {getPropValue, FormControlProps} from 'amis-core';
|
||||
import {ErrorBoundary} from 'react-error-boundary';
|
||||
import {ErrorBoundary} from 'amis-core';
|
||||
|
||||
function renderCommonStatic(props: any, defaultValue: string) {
|
||||
const {type, render, staticSchema} = props;
|
||||
@ -135,11 +134,19 @@ export function supportStatic<T extends FormControlProps>() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx(`${ns}Form-static`, className)}>
|
||||
<ErrorBoundary fallback={<>{toString(body)}</>}>
|
||||
{body}
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
<ErrorBoundary
|
||||
customErrorMsg={`拦截到${props.$schema.type}渲染错误,当前组件schema: ${props.$schema}`}
|
||||
fallback={() => {
|
||||
return (
|
||||
<div className="renderer-error-boundary">
|
||||
{props.$schema?.type}
|
||||
渲染发生错误,详细错误信息请查看控制台输出。
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className={cx(`${ns}Form-static`, className)}>{body}</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user