|
1 | 1 | import { cloneEnumerableProperty } from '@alilc/lowcode-utils'; |
2 | 2 | import adapter from '../adapter'; |
| 3 | +import { IBaseRendererInstance, IRendererProps } from '../types'; |
3 | 4 |
|
4 | | -export function compWrapper(Comp: any) { |
| 5 | +function patchDidCatch(Comp: any, { baseRenderer }: { baseRenderer: IBaseRendererInstance }) { |
| 6 | + if (Comp.patchedCatch) { |
| 7 | + return; |
| 8 | + } |
| 9 | + Comp.patchedCatch = true; |
| 10 | + const { PureComponent } = adapter.getRuntime(); |
| 11 | + // Rax 的 getDerivedStateFromError 有 BUG,这里先用 componentDidCatch 来替代 |
| 12 | + // @see https://github.com/alibaba/rax/issues/2211 |
| 13 | + const originalDidCatch = Comp.prototype.componentDidCatch; |
| 14 | + Comp.prototype.componentDidCatch = function didCatch(this: any, error: Error, errorInfo: any) { |
| 15 | + this.setState({ engineRenderError: true, error }); |
| 16 | + if (originalDidCatch && typeof originalDidCatch === 'function') { |
| 17 | + originalDidCatch.call(this, error, errorInfo); |
| 18 | + } |
| 19 | + }; |
| 20 | + |
| 21 | + const { engine } = baseRenderer.context; |
| 22 | + const originRender = Comp.prototype.render; |
| 23 | + Comp.prototype.render = function () { |
| 24 | + if (this.state && this.state.engineRenderError) { |
| 25 | + this.state.engineRenderError = false; |
| 26 | + return engine.createElement(engine.getFaultComponent(), { |
| 27 | + ...this.props, |
| 28 | + error: this.state.error, |
| 29 | + componentName: this.props._componentName, |
| 30 | + }); |
| 31 | + } |
| 32 | + return originRender.call(this); |
| 33 | + }; |
| 34 | + if (!(Comp.prototype instanceof PureComponent)) { |
| 35 | + const originShouldComponentUpdate = Comp.prototype.shouldComponentUpdate; |
| 36 | + Comp.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) { |
| 37 | + if (nextState && nextState.engineRenderError) { |
| 38 | + return true; |
| 39 | + } |
| 40 | + return originShouldComponentUpdate |
| 41 | + ? originShouldComponentUpdate.call(this, nextProps, nextState) |
| 42 | + : true; |
| 43 | + }; |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererInstance }) { |
5 | 48 | const { createElement, Component, forwardRef } = adapter.getRuntime(); |
| 49 | + if ( |
| 50 | + Comp?.prototype?.isReactComponent || // react |
| 51 | + Comp?.prototype?.setState || // rax |
| 52 | + Comp?.prototype instanceof Component |
| 53 | + ) { |
| 54 | + patchDidCatch(Comp, options); |
| 55 | + return Comp; |
| 56 | + } |
6 | 57 | class Wrapper extends Component { |
7 | | - // constructor(props: any, context: any) { |
8 | | - // super(props, context); |
9 | | - // } |
10 | | - |
11 | 58 | render() { |
12 | | - return createElement(Comp, this.props); |
| 59 | + return createElement(Comp, { ...this.props, ref: this.props.forwardRef }); |
13 | 60 | } |
14 | 61 | } |
15 | 62 | (Wrapper as any).displayName = Comp.displayName; |
16 | 63 |
|
17 | | - return cloneEnumerableProperty(forwardRef((props: any, ref: any) => { |
18 | | - return createElement(Wrapper, { ...props, forwardRef: ref }); |
19 | | - }), Comp); |
| 64 | + patchDidCatch(Wrapper, options); |
| 65 | + |
| 66 | + return cloneEnumerableProperty( |
| 67 | + forwardRef((props: any, ref: any) => { |
| 68 | + return createElement(Wrapper, { ...props, forwardRef: ref }); |
| 69 | + }), |
| 70 | + Comp, |
| 71 | + ); |
20 | 72 | } |
0 commit comments