diff --git a/packages/designer/tests/document/document-model/__snapshots__/document-model.test.ts.snap b/packages/designer/tests/document/document-model/__snapshots__/document-model.test.ts.snap index 779fdd751..23ebe6842 100644 --- a/packages/designer/tests/document/document-model/__snapshots__/document-model.test.ts.snap +++ b/packages/designer/tests/document/document-model/__snapshots__/document-model.test.ts.snap @@ -72,7 +72,6 @@ Object { "hidden": false, "id": "node_k1ow3cbd", "isLocked": false, - "loop": undefined, "props": Object { "__slot__action": false, "__slot__content": false, @@ -121,7 +120,6 @@ Object { "hidden": false, "id": "node_k1ow3cba", "isLocked": false, - "loop": undefined, "props": Object {}, "title": "", }, @@ -144,7 +142,6 @@ Object { "hidden": false, "id": "node_k1ow3cbz", "isLocked": false, - "loop": undefined, "props": Object { "__category__": "form", "__style__": Object {}, @@ -223,7 +220,6 @@ Object { "hidden": false, "id": "node_k1ow3cc1", "isLocked": false, - "loop": undefined, "props": Object { "__category__": "form", "__style__": Object {}, @@ -298,7 +294,6 @@ Object { "hidden": false, "id": "node_k1ow3cc3", "isLocked": false, - "loop": undefined, "props": Object { "__category__": "form", "__style__": Object {}, @@ -373,7 +368,6 @@ Object { "hidden": false, "id": "node_k1ow3cbx", "isLocked": false, - "loop": undefined, "props": Object { "__style__": Object {}, "colSpan": "", @@ -390,7 +384,6 @@ Object { "hidden": false, "id": "node_k1ow3cc2", "isLocked": false, - "loop": undefined, "props": Object { "__category__": "form", "__style__": Object {}, @@ -465,7 +458,6 @@ Object { "hidden": false, "id": "node_k1ow3cc0", "isLocked": false, - "loop": undefined, "props": Object { "__category__": "form", "__style__": Object {}, @@ -560,7 +552,6 @@ Object { "hidden": false, "id": "node_k1ow3cby", "isLocked": false, - "loop": undefined, "props": Object { "__style__": Object {}, "colSpan": "", @@ -575,7 +566,6 @@ Object { "hidden": false, "id": "node_k1ow3cbw", "isLocked": false, - "loop": undefined, "props": Object { "__style__": Object {}, "columnGap": "20", @@ -592,7 +582,6 @@ Object { "hidden": false, "id": "node_k1ow3cbk", "isLocked": false, - "loop": undefined, "props": Object {}, "title": "", }, @@ -603,7 +592,6 @@ Object { "hidden": false, "id": "node_k1ow3cbj", "isLocked": false, - "loop": undefined, "props": Object { "__slot__extra": false, "__slot__subTitle": false, @@ -648,7 +636,6 @@ Object { "hidden": false, "id": "node_k1ow3cc4", "isLocked": false, - "loop": undefined, "props": Object { "__category__": "form", "__style__": Object {}, @@ -727,7 +714,6 @@ Object { "hidden": false, "id": "node_k1ow3cc8", "isLocked": false, - "loop": undefined, "props": Object { "__category__": "form", "__style__": Object {}, @@ -802,7 +788,6 @@ Object { "hidden": false, "id": "node_k1ow3cc6", "isLocked": false, - "loop": undefined, "props": Object { "__style__": Object {}, "colSpan": "", @@ -819,7 +804,6 @@ Object { "hidden": false, "id": "node_k1ow3cc9", "isLocked": false, - "loop": undefined, "props": Object { "__category__": "form", "__style__": Object {}, @@ -894,7 +878,6 @@ Object { "hidden": false, "id": "node_k1ow3cc7", "isLocked": false, - "loop": undefined, "props": Object { "__style__": Object {}, "colSpan": "", @@ -909,7 +892,6 @@ Object { "hidden": false, "id": "node_k1ow3cc5", "isLocked": false, - "loop": undefined, "props": Object { "__style__": Object {}, "columnGap": "20", @@ -926,7 +908,6 @@ Object { "hidden": false, "id": "node_k1ow3cbm", "isLocked": false, - "loop": undefined, "props": Object {}, "title": "", }, @@ -937,7 +918,6 @@ Object { "hidden": false, "id": "node_k1ow3cbl", "isLocked": false, - "loop": undefined, "props": Object { "__slot__extra": false, "__slot__subTitle": false, @@ -980,7 +960,6 @@ Object { "hidden": false, "id": "node_k1ow3cbn", "isLocked": false, - "loop": undefined, "props": Object { "__style__": ":root { margin-right: 16px; @@ -1025,7 +1004,6 @@ Object { "hidden": false, "id": "node_k1ow3cbp", "isLocked": false, - "loop": undefined, "props": Object { "__style__": ":root { width: 80px; @@ -1063,7 +1041,6 @@ Object { "hidden": false, "id": "node_k1ow3cbo", "isLocked": false, - "loop": undefined, "props": Object { "__style__": ":root { display: flex; @@ -1089,7 +1066,6 @@ Object { "hidden": false, "id": "form", "isLocked": false, - "loop": undefined, "props": Object { "__style__": Object {}, "autoUnmount": true, @@ -1120,7 +1096,6 @@ Object { "hidden": false, "id": "node_k1ow3cbb", "isLocked": false, - "loop": undefined, "props": Object { "contentBgColor": "transparent", "contentMargin": "20", @@ -1135,7 +1110,6 @@ Object { "hidden": false, "id": "node_k1ow3cbc", "isLocked": false, - "loop": undefined, "props": Object {}, "title": "", }, @@ -1203,7 +1177,6 @@ Object.keys(module.exports).forEach(function(item) { "type": "js", }, }, - "loop": undefined, "methods": Object { "__initMethods__": Object { "compiled": "function (exports, module) { /*set actions code here*/ }", diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index 79a466e97..81334e96c 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -16,9 +16,8 @@ import { isPlainObject, AssetLoader, getProjectUtils, - applyActivities, } from '@ali/lowcode-utils'; -import { RootSchema, ComponentSchema, TransformStage, NodeSchema, ActivityType, ActivityData } from '@ali/lowcode-types'; +import { ComponentSchema, TransformStage, NodeSchema } from '@ali/lowcode-types'; // just use types import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel, Node } from '@ali/lowcode-designer'; import LowCodeRenderer from '@ali/lowcode-react-renderer'; @@ -28,8 +27,6 @@ import Leaf from './builtin-components/leaf'; import { withQueryParams, parseQuery } from './utils/url'; const loader = new AssetLoader(); -const DELAY_THRESHOLD = 10; -const FULL_RENDER_THRESHOLD = 500; configure({ enforceActions: 'never' }); export class DocumentInstance { @@ -447,16 +444,11 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { class LowCodeComp extends React.Component { render() { - const newSchema = host.designer.transformProps(_schema as any, { - componentMeta: { - prototype: 'lowcodeComp', - }, - isRoot: () => false, - } as Node, TransformStage.Render); const extraProps = getLowCodeComponentProps(this.props); return createElement(LowCodeRenderer, { ...extraProps, // 防止覆盖下面内置属性 - schema: newSchema, + // 使用 _schema 为了使低代码组件在页面设计中使用变量,同 react 组件使用效果一致 + schema: _schema, components: renderer.components, designMode: renderer.designMode, device: renderer.device, diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index c309e6e84..f40522a58 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -26,7 +26,6 @@ export type IComponentHoc = { }; export type IComponentConstruct = (Comp: types.IBaseRenderer, info: IComponentHocInfo) => types.Constructor; - // const whitelist: string[] = []; interface IProps { @@ -50,6 +49,63 @@ enum RerenderType { I18nChanged = 'I18nChanged', } +// 缓存 Leaf 层组件,防止重新渲染问题 +const leafComponentCache: { + [componentName: string]: any; +} = {}; +// 缓存导致 rerender 的订阅事件 +const rerenderEventCache: { + [componentId: string]: any; +} = {}; + +/** 部分没有渲染的 node 节点进行兜底处理 or 渲染方式没有渲染 LeafWrapper */ +function makeRerenderEvent({ + schema, + __debug, + container, + getNode, +}: any) { + const leaf = getNode?.(schema.id); + if (!leaf + || rerenderEventCache[schema.id]?.clear + || leaf === rerenderEventCache[schema.id]?.leaf + ) { + return; + } + rerenderEventCache[schema.id]?.dispose.forEach((d: any) => d && d()); + rerenderEventCache[schema.id] = { + clear: false, + leaf, + dispose: [ + leaf?.onPropChange?.(() => { + __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onPropsChange make rerender`); + container.rerender(); + }), + leaf?.onChildrenChange?.(() => { + __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onChildrenChange make rerender`); + container.rerender(); + }) as Function, + leaf?.onVisibleChange?.(() => { + __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onVisibleChange make rerender`); + container.rerender(); + }), + ], + }; +} + +/** 渲染的 node 节点全局注册事件清除 */ +function clearRerenderEvent(id: string): void { + if (!rerenderEventCache[id]) { + rerenderEventCache[id] = { + clear: true, + }; + return; + } + rerenderEventCache[id].dispose.forEach((d: any) => d && d()); + rerenderEventCache[id].dispose = []; + rerenderEventCache[id].clear = true; +} + // 给每个组件包裹一个 HOC Leaf,支持组件内部属性变化,自响应渲染 export function leafWrapper(Comp: types.IBaseRenderer, { schema, @@ -72,16 +128,15 @@ export function leafWrapper(Comp: types.IBaseRenderer, { console.error(`${schema.componentName} component may be has errors: `, Comp); } - /** 部分没有渲染的 node 节点进行兜底处理 or 渲染方式没有渲染 LeafWrapper */ - let wrapDisposeFunctions: Function[] = []; - if (getNode) { - const leaf = getNode(schema.id); + makeRerenderEvent({ + schema, + __debug, + container, + getNode, + }); - wrapDisposeFunctions = [ - leaf?.onPropsChange?.(() => container.rerender()), - leaf?.onChildrenChange?.(() => container.rerender()), - leaf?.onVisibleChange?.(() => container.rerender()), - ]; + if (leafComponentCache[schema.componentName]) { + return leafComponentCache[schema.componentName]; } class LeafWrapper extends Component { @@ -94,6 +149,8 @@ export function leafWrapper(Comp: types.IBaseRenderer, { disposeFunctions: ((() => void) | Function)[] = []; + __component_tag = 'leafWrapper'; + recordTime = () => { if (!this.recordInfo.startTime) { return; @@ -117,10 +174,11 @@ export function leafWrapper(Comp: types.IBaseRenderer, { constructor(props: IProps, context: any) { super(props, context); // 监听以下事件,当变化时更新自己 + clearRerenderEvent(schema.id); this.initOnPropsChangeEvent(); this.initOnChildrenChangeEvent(); this.initOnVisibleChangeEvent(); - wrapDisposeFunctions.forEach(d => d && d()); + __debug(`${schema.componentName}[${schema.id}] leaf render in SimulatorRendererView`); this.state = { nodeChildren: null, childrenInState: false, @@ -324,5 +382,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, { LeafWrapper.displayName = (Comp as any).displayName; + leafComponentCache[schema.componentName] = LeafWrapper; + return LeafWrapper; } \ No newline at end of file diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 5018342bb..87f4ad919 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -62,8 +62,6 @@ export default function baseRenererFactory() { static contextType = AppContext; - __hoc_components: any = {}; - __namespace = 'base'; _self: any = null; @@ -481,28 +479,20 @@ export default function baseRenererFactory() { props: transformArrayToMap(componentInfo.props, 'name'), }) || {}; - if (!this.__hoc_components[schema.componentName]) { - this.componentHoc.forEach((ComponentConstruct: IComponentConstruct) => { - Comp = ComponentConstruct(Comp, { - schema, - componentInfo, - baseRenderer: this, - }); + this.componentHoc.forEach((ComponentConstruct: IComponentConstruct) => { + Comp = ComponentConstruct(Comp, { + schema, + componentInfo, + baseRenderer: this, }); - } + }); // 对于可以获取到ref的组件做特殊处理 - if (!acceptsRef(Comp) && !this.__hoc_components[schema.componentName]) { + if (!acceptsRef(Comp)) { Comp = compWrapper(Comp); components[schema.componentName] = Comp; } - if (!this.__hoc_components[schema.componentName]) { - this.__hoc_components[schema.componentName] = Comp; - } else { - Comp = this.__hoc_components[schema.componentName]; - } - otherProps.ref = (ref: any) => { this.$(props.fieldId || props.ref, ref); // 收集ref const refProps = props.ref; @@ -824,18 +814,13 @@ export default function baseRenererFactory() { }; __getHocComp(Comp: any, schema: any) { - if (!this.__hoc_components[schema.componentName]) { - this.componentHoc.forEach((ComponentConstruct: IComponentConstruct) => { - Comp = ComponentConstruct(Comp || Div, { - schema, - componentInfo: {}, - baseRenderer: this, - }); + this.componentHoc.forEach((ComponentConstruct: IComponentConstruct) => { + Comp = ComponentConstruct(Comp || Div, { + schema, + componentInfo: {}, + baseRenderer: this, }); - this.__hoc_components[schema.componentName] = Comp; - } else { - Comp = this.__hoc_components[schema.componentName]; - } + }); return Comp; }