add error catch

This commit is contained in:
kangwei 2020-05-07 22:12:37 +08:00
parent fb918a10be
commit db35986635
2 changed files with 223 additions and 153 deletions

View File

@ -197,6 +197,7 @@ export default class BaseEngine extends PureComponent {
// parentInfo schemaComp // parentInfo schemaComp
// idx Index // idx Index
__createVirtualDom = (schema, self, parentInfo, idx) => { __createVirtualDom = (schema, self, parentInfo, idx) => {
try {
if (!schema) return null; if (!schema) return null;
const { __appHelper: appHelper, __components: components = {} } = const { __appHelper: appHelper, __components: components = {} } =
this.props || {}; this.props || {};
@ -226,7 +227,7 @@ export default class BaseEngine extends PureComponent {
} }
if (!isSchema(schema)) return null; if (!isSchema(schema)) return null;
let Comp = components[schema.componentName] || Div; let Comp = components[schema.componentName] || engine.getNotFoundComponent();
if (schema.hidden) { if (schema.hidden) {
return null; return null;
@ -359,6 +360,15 @@ export default class BaseEngine extends PureComponent {
} }
} }
return renderComp({ ...props, ...otherProps }); return renderComp({ ...props, ...otherProps });
} catch (e) {
return engine.createElement(engine.getFaultComponent(), {
error: e,
schema,
self,
parentInfo,
idx,
});
}
}; };
__createLoopVirtualDom = (schema, self, parentInfo, idx) => { __createLoopVirtualDom = (schema, self, parentInfo, idx) => {

View File

@ -1,4 +1,4 @@
import React, { PureComponent, createElement as reactCreateElement } from 'react'; import React, { Component, PureComponent, createElement as reactCreateElement } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Debug from 'debug'; import Debug from 'debug';
@ -11,6 +11,7 @@ import AddonEngine from './addonEngine';
import TempEngine from './tempEngine'; import TempEngine from './tempEngine';
import { isEmpty } from '@ali/b3-one/lib/obj'; import { isEmpty } from '@ali/b3-one/lib/obj';
import BaseEngine from './base'; import BaseEngine from './base';
import Div from '@ali/iceluna-comp-div';
window.React = React; window.React = React;
window.ReactDom = ReactDOM; window.ReactDom = ReactDOM;
@ -23,6 +24,26 @@ const ENGINE_COMPS = {
AddonEngine, AddonEngine,
TempEngine, TempEngine,
}; };
class FaultComponent extends PureComponent {
render() {
// FIXME: errorlog
console.error('render error', this.props);
return <Div>RenderError</Div>;
}
}
class NotFoundComponent extends PureComponent {
render() {
console.error('component not found', this.props);
return <Div {...this.props} />;
}
}
function isReactClass(obj) {
return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component);
}
export default class Engine extends PureComponent { export default class Engine extends PureComponent {
static dislayName = 'engine'; static dislayName = 'engine';
static propTypes = { static propTypes = {
@ -86,9 +107,48 @@ export default class Engine extends PureComponent {
} }
}; };
patchDidCatch(Component) {
if (!isReactClass(Component)) {
return;
}
if (Component.patchedCatch) {
return;
}
Component.patchedCatch = true;
Component.getDerivedStateFromError = (error) => {
return { engineRenderError: true, error };
};
const engine = this;
const originRender = Component.prototype.render;
Component.prototype.render = function () {
if (this.state && this.state.engineRenderError) {
return engine.createElement(this.getFaultComponent(), {
error: this.state.error,
props: this.props,
});
}
return originRender.call(this);
};
const originShouldComponentUpdate = Component.prototype.shouldComponentUpdate;
Component.prototype.shouldComponentUpdate = function (nextProps, nextState) {
if (nextState && nextState.engineRenderError) {
return true;
}
return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true;
};
}
createElement(Component, props, children) { createElement(Component, props, children) {
// TODO: enable in runtime mode?
this.patchDidCatch(Component);
return (this.props.customCreateElement || reactCreateElement)(Component, props, children); return (this.props.customCreateElement || reactCreateElement)(Component, props, children);
} }
getNotFoundComponent() {
return this.props.notFoundComponent || NotFoundComponent;
}
getFaultComponent() {
return this.props.faultComponent || FaultComponent;
}
render() { render() {
const { schema, designMode, appHelper, components, customCreateElement } = this.props; const { schema, designMode, appHelper, components, customCreateElement } = this.props;