diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx index 09559b6f8..57fbf5121 100644 --- a/packages/renderer-core/src/renderer/renderer.tsx +++ b/packages/renderer-core/src/renderer/renderer.tsx @@ -7,9 +7,10 @@ import divFactory from '../components/Div'; import { IRenderComponent, IRendererProps, IRendererState } from '../types'; import { IPublicTypeNodeSchema, IPublicTypeRootSchema } from '@alilc/lowcode-types'; import logger from '../utils/logger'; +import { cloneEnumerableProperty, isForwardRefType, wrapReactClass } from '@alilc/lowcode-utils'; export default function rendererFactory(): IRenderComponent { - const { PureComponent, Component, createElement, findDOMNode } = adapter.getRuntime(); + const { PureComponent, Component, createElement, findDOMNode, forwardRef } = adapter.getRuntime(); const RENDERER_COMPS: any = adapter.getRenderers(); const BaseRenderer = baseRendererFactory(); const AppContext = contextFactory(); @@ -105,18 +106,7 @@ export default function rendererFactory(): IRenderComponent { return SetComponent; } - patchDidCatch(SetComponent: any) { - if (!this.isValidComponent(SetComponent)) { - return; - } - if (SetComponent.patchedCatch) { - return; - } - if (!SetComponent.prototype) { - return; - } - SetComponent.patchedCatch = true; - + patchDidCatchForClassComponent(SetComponent: any) { // Rax 的 getDerivedStateFromError 有 BUG,这里先用 componentDidCatch 来替代 // @see https://github.com/alibaba/rax/issues/2211 const originalDidCatch = SetComponent.prototype.componentDidCatch; @@ -135,12 +125,12 @@ export default function rendererFactory(): IRenderComponent { return engine.createElement(engine.getFaultComponent(), { ...this.props, error: this.state.error, - componentName: this.props._componentName + componentName: this.props._componentName, }); } return originRender.call(this); }; - if(!(SetComponent.prototype instanceof PureComponent)) { + if (!(SetComponent.prototype instanceof PureComponent)) { const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate; SetComponent.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) { if (nextState && nextState.engineRenderError) { @@ -151,10 +141,37 @@ export default function rendererFactory(): IRenderComponent { } } + patchDidCatch(SetComponent: any) { + if (isForwardRefType(SetComponent)) { + SetComponent.patchedCatch = true; + const Wrapper = wrapReactClass(SetComponent); + this.patchDidCatchForClassComponent(Wrapper); + return cloneEnumerableProperty( + forwardRef((props: any, ref: any) => { + return createElement(Wrapper, { ...props, forwardRef: ref }); + }), + SetComponent, + ); + } + + if (!this.isValidComponent(SetComponent)) { + return; + } + if (SetComponent.patchedCatch) { + return; + } + + if (!SetComponent.prototype) { + return; + } + SetComponent.patchedCatch = true; + this.patchDidCatchForClassComponent(SetComponent); + } + createElement(SetComponent: any, props: any, children?: any) { // TODO: enable in runtime mode? - this.patchDidCatch(SetComponent); - return (this.props.customCreateElement || createElement)(SetComponent, props, children); + const PatchedComponent = this.patchDidCatch(SetComponent) || SetComponent; + return (this.props.customCreateElement || createElement)(PatchedComponent, props, children); } getNotFoundComponent() { diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts index a49fe8992..afbec272a 100644 --- a/packages/renderer-core/src/types/index.ts +++ b/packages/renderer-core/src/types/index.ts @@ -335,7 +335,6 @@ export interface IRenderComponent { componentDidCatch(e: any): Promise | void; shouldComponentUpdate(nextProps: IRendererProps): boolean; isValidComponent(SetComponent: any): any; - patchDidCatch(SetComponent: any): void; createElement(SetComponent: any, props: any, children?: any): any; getNotFoundComponent(): any; getFaultComponent(): any; diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index 07568db98..94279875f 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -13,7 +13,7 @@ export function acceptsRef(obj: any): boolean { return obj?.prototype?.isReactComponent || (obj.$$typeof && obj.$$typeof === REACT_FORWARD_REF_TYPE); } -function isForwardRefType(obj: any): boolean { +export function isForwardRefType(obj: any): boolean { return obj?.$$typeof && obj?.$$typeof === REACT_FORWARD_REF_TYPE; }