diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js
index 553eeb33f..b32307826 100644
--- a/packages/designer/jest.config.js
+++ b/packages/designer/jest.config.js
@@ -6,7 +6,7 @@ module.exports = {
// // '^.+\\.(ts|tsx)$': 'ts-jest',
// // '^.+\\.(js|jsx)$': 'babel-jest',
// },
- // testMatch: ['**/builtin-hotkey.test.ts'],
+ testMatch: ['**/bugs/*.test.ts'],
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`,
diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts
index 6b9e70f13..c493da22d 100644
--- a/packages/designer/src/document/document-model.ts
+++ b/packages/designer/src/document/document-model.ts
@@ -198,7 +198,7 @@ export class DocumentModel {
* 根据 id 获取节点
*/
getNodeCount(): number {
- return this._nodesMap.size;
+ return this._nodesMap?.size;
}
/**
diff --git a/packages/designer/tests/bugs/misc.ts b/packages/designer/tests/bugs/misc.ts.bak
similarity index 100%
rename from packages/designer/tests/bugs/misc.ts
rename to packages/designer/tests/bugs/misc.ts.bak
diff --git a/packages/designer/tests/bugs/prop-variable-jse.test.ts b/packages/designer/tests/bugs/prop-variable-jse.test.ts
new file mode 100644
index 000000000..c830f8fbd
--- /dev/null
+++ b/packages/designer/tests/bugs/prop-variable-jse.test.ts
@@ -0,0 +1,72 @@
+// @ts-nocheck
+import { Editor } from '@ali/lowcode-editor-core';
+import { isJSBlock, TransformStage } from '@ali/lowcode-types';
+import { isPlainObject, isVariable } from '@ali/lowcode-utils';
+import '../fixtures/window';
+import { Designer } from '../../src/designer/designer';
+import { DocumentModel } from '../../src/document/document-model';
+import { Project } from '../../src/project/project';
+import formSchema from '../fixtures/schema/form';
+
+/**
+ * bug 背景:
+ * Prop 在每次 setValue 时都会调用 dispose 方法用于重新计算子 Prop,我认为在 Node 未完成初始化之前的 dispose 都是
+ * 无意义的,所以增加了判断条件来调用 dispose,结果导致了 variable 结果没有正确转成 JSExpression 结构。
+ *
+ * 因为 propsReducer 的 Init / Upgrade 阶段依然可以更改 props,且此时的 Node 也未完成初始化,不调用 dispose 则导致新的 Prop 结构无法生效
+ */
+
+function upgradePropsReducer(props: any): any {
+ if (!props || !isPlainObject(props)) {
+ return props;
+ }
+
+ if (isJSBlock(props)) {
+ if (props.value.componentName === 'Slot') {
+ return {
+ type: 'JSSlot',
+ title: (props.value.props as any)?.slotTitle,
+ name: (props.value.props as any)?.slotName,
+ value: props.value.children,
+ };
+ } else {
+ return props.value;
+ }
+ }
+ if (isVariable(props)) {
+ return {
+ type: 'JSExpression',
+ value: props.variable,
+ mock: props.value,
+ };
+ }
+ const newProps: any = {};
+ Object.keys(props).forEach((key) => {
+ if (/^__slot__/.test(key) && props[key] === true) {
+ return;
+ }
+ newProps[key] = upgradePropsReducer(props[key]);
+ });
+ return newProps;
+}
+
+describe('Node 方法测试', () => {
+ let editor: Editor;
+ let designer: Designer;
+ let project: Project;
+ let doc: DocumentModel;
+
+ it('原始 prop 值是 variable 结构,通过一个 propsReducer 转成了 JSExpression 结构', () => {
+ editor = new Editor();
+ designer = new Designer({ editor });
+ designer.addPropsReducer(upgradePropsReducer, TransformStage.Upgrade);
+ project = designer.project;
+ doc = new DocumentModel(project, formSchema);
+
+ const form = doc.getNode('form');
+ expect(form.getPropValue('dataSource')).toEqual({
+ type: 'JSExpression',
+ value: 'state.formData',
+ })
+ });
+});
diff --git a/packages/designer/tests/bugs/why.md b/packages/designer/tests/bugs/why.md
new file mode 100644
index 000000000..519dee1b5
--- /dev/null
+++ b/packages/designer/tests/bugs/why.md
@@ -0,0 +1,6 @@
+背景:
+在 UT 的基础上,希望借助一些 Bug 修复来完成场景测试,从而进一步增强稳定性。
+至少在真正的 E2E 测试来临之前,我们保证不会重复犯两次相同的错误。
+
+做法:
+Bugs 文件夹每个文件记录一个 bug 修复的场景测试~
\ No newline at end of file
diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts
index 18f40e215..ee3928a64 100644
--- a/packages/designer/tests/document/node/node.test.ts
+++ b/packages/designer/tests/document/node/node.test.ts
@@ -1,4 +1,4 @@
-// @ts-ignore
+// @ts-nocheck
import '../../fixtures/window';
import { set, delayObxTick, delay } from '../../utils';
import { Editor } from '@ali/lowcode-editor-core';
@@ -24,7 +24,6 @@ import rootHeaderMetadata from '../../fixtures/component-metadata/root-header';
import rootContentMetadata from '../../fixtures/component-metadata/root-content';
import rootFooterMetadata from '../../fixtures/component-metadata/root-footer';
-
describe('Node 方法测试', () => {
let editor: Editor;
let designer: Designer;
@@ -185,12 +184,16 @@ describe('Node 方法测试', () => {
it('null', () => {
expect(
- doc.rootNode?.getSuitablePlace.call({ contains: () => false, isContainer: () => false, isRoot: () => false }),
+ doc.rootNode?.getSuitablePlace.call({
+ contains: () => false,
+ isContainer: () => false,
+ isRoot: () => false,
+ }),
).toBeNull();
});
});
- it('removeChild / replaceWith / replaceChild / onChildrenChange / mergeChildren', () => {
+ it('removeChild / replaceWith / replaceChild', () => {
const firstBtn = doc.getNode('node_k1ow3cbn')!;
firstBtn.select();
@@ -254,7 +257,7 @@ describe('Node 方法测试', () => {
});
});
- it('setVisible / getVisible / onVisibleChange', async () => {
+ it('setVisible / getVisible / onVisibleChange', () => {
const mockFn = jest.fn();
const firstBtn = doc.getNode('node_k1ow3cbn')!;
const off = firstBtn.onVisibleChange(mockFn);
@@ -265,7 +268,6 @@ describe('Node 方法测试', () => {
firstBtn.setVisible(false);
- await delayObxTick();
expect(firstBtn.getVisible()).toBeFalsy();
expect(mockFn).toHaveBeenCalledTimes(2);
expect(mockFn).toHaveBeenCalledWith(false);
@@ -273,7 +275,22 @@ describe('Node 方法测试', () => {
off();
mockFn.mockClear();
firstBtn.setVisible(true);
- await delayObxTick();
+ expect(mockFn).not.toHaveBeenCalled();
+ });
+
+ it('onPropChange', () => {
+ const mockFn = jest.fn();
+ const firstBtn = doc.getNode('node_k1ow3cbn')!;
+ const off = firstBtn.onPropChange(mockFn);
+
+ firstBtn.setPropValue('x', 1);
+ expect(mockFn).toHaveBeenCalledTimes(1);
+ firstBtn.setPropValue('x', 2);
+ expect(mockFn).toHaveBeenCalledTimes(2);
+
+ off();
+ mockFn.mockClear();
+ firstBtn.setPropValue('x', 3);
expect(mockFn).not.toHaveBeenCalled();
});
@@ -292,7 +309,9 @@ describe('Node 方法测试', () => {
const pageMeta = designer.getComponentMeta('Page');
const autorunMockFn = jest.fn();
- set(pageMeta, '_transformedMetadata.experimental.autoruns', [{ name: 'a', autorun: autorunMockFn }]);
+ set(pageMeta, '_transformedMetadata.experimental.autoruns', [
+ { name: 'a', autorun: autorunMockFn },
+ ]);
const initialChildrenMockFn = jest.fn();
set(pageMeta, '_transformedMetadata.experimental.initialChildren', initialChildrenMockFn);
doc.createNode({ componentName: 'Page', props: { a: 1 } });
diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts
index 1b55890f1..76ed65af6 100644
--- a/packages/designer/tests/document/node/props/prop.test.ts
+++ b/packages/designer/tests/document/node/props/prop.test.ts
@@ -200,9 +200,11 @@ describe('Prop 类测试', () => {
// 更新 slot
slotProp.setValue({
type: 'JSSlot',
- value: [{
- componentName: 'Form',
- }]
+ value: [
+ {
+ componentName: 'Form',
+ },
+ ],
});
expect(slotNodeImportMockFn).toBeCalled();
@@ -276,19 +278,20 @@ describe('Prop 类测试', () => {
expect(prop.get('z.z1')?.getValue()).toBe(1);
expect(prop.get('z.z2')?.getValue()).toBe('str');
- const fromStashProp = prop.get('l');
- const fromStashNestedProp = prop.get('m.m1');
- fromStashProp.setValue('fromStashProp');
- fromStashNestedProp?.setValue('fromStashNestedProp');
+ const newlyCreatedProp = prop.get('l', true);
+ const newlyCreatedNestedProp = prop.get('m.m1', true);
+ newlyCreatedProp.setValue('newlyCreatedProp');
+ newlyCreatedNestedProp?.setValue('newlyCreatedNestedProp');
- await delayObxTick();
- expect(prop.get('l').getValue()).toBe('fromStashProp');
- expect(prop.get('m.m1').getValue()).toBe('fromStashNestedProp');
+ expect(prop.get('l').getValue()).toBe('newlyCreatedProp');
+ expect(prop.get('m.m1').getValue()).toBe('newlyCreatedNestedProp');
+
+ const newlyCreatedNestedProp2 = prop.get('m.m2', true);
+ // .m2 的值为 undefined,导出时将会被移除
+ expect(prop.get('m').getValue()).toEqual({ m1: 'newlyCreatedNestedProp' });
});
it('export', () => {
- // TODO: 需要访问一下才能触发构造 _items
- prop.items;
expect(prop.export()).toEqual({
a: 1,
b: 'str',
diff --git a/packages/designer/tests/document/node/props/props.test.ts b/packages/designer/tests/document/node/props/props.test.ts
index eb49568a5..360db47eb 100644
--- a/packages/designer/tests/document/node/props/props.test.ts
+++ b/packages/designer/tests/document/node/props/props.test.ts
@@ -2,32 +2,42 @@
import '../../../fixtures/window';
import { set, delayObxTick } from '../../../utils';
import { Editor } from '@ali/lowcode-editor-core';
-import { Props, getConvertedExtraKey, getOriginalExtraKey, Prop, isProp, isValidArrayIndex } from '../../../../src/document/node/props/props';
+import {
+ Props,
+ getConvertedExtraKey,
+ getOriginalExtraKey,
+ Prop,
+ isProp,
+ isValidArrayIndex,
+} from '../../../../src/document/node/props/props';
import { Designer } from '../../../../src/designer/designer';
import { Project } from '../../../../src/project/project';
import { DocumentModel } from '../../../../src/document/document-model';
import { TransformStage } from '@ali/lowcode-types';
-
const mockedOwner = { componentName: 'Page' };
describe('Props 类测试', () => {
let props: Props;
beforeEach(() => {
- props = new Props(mockedOwner, {
- a: 1,
- b: 'str',
- c: true,
- d: {
- type: 'JSExpression',
- value: 'state.a',
+ props = new Props(
+ mockedOwner,
+ {
+ a: 1,
+ b: 'str',
+ c: true,
+ d: {
+ type: 'JSExpression',
+ value: 'state.a',
+ },
+ z: {
+ z1: 1,
+ z2: 'str',
+ },
},
- z: {
- z1: 1,
- z2: 'str',
- },
- }, { condition: true });
+ { condition: true },
+ );
});
afterEach(() => {
props.purge();
@@ -49,7 +59,6 @@ describe('Props 类测试', () => {
z2: 'str',
});
-
expect(props.getPropValue('a')).toBe(1);
props.setPropValue('a', 2);
expect(props.getPropValue('a')).toBe(2);
@@ -59,14 +68,15 @@ describe('Props 类测试', () => {
expect(props.get('z.z1')?.getValue()).toBe(1);
expect(props.get('z.z2')?.getValue()).toBe('str');
- const fromStashProp = props.get('l', true);
- const fromStashNestedProp = props.get('m.m1', true);
- fromStashProp.setValue('fromStashProp');
- fromStashNestedProp?.setValue('fromStashNestedProp');
+ const notCreatedProp = props.get('i');
+ expect(notCreatedProp).toBeNull();
+ const newlyCreatedProp = props.get('l', true);
+ const newlyCreatedNestedProp = props.get('m.m1', true);
+ newlyCreatedProp.setValue('newlyCreatedProp');
+ newlyCreatedNestedProp?.setValue('newlyCreatedNestedProp');
- await delayObxTick();
- expect(props.get('l').getValue()).toBe('fromStashProp');
- expect(props.get('m.m1').getValue()).toBe('fromStashNestedProp');
+ expect(props.get('l').getValue()).toBe('newlyCreatedProp');
+ expect(props.get('m.m1').getValue()).toBe('newlyCreatedNestedProp');
});
it('export', () => {
@@ -119,11 +129,66 @@ describe('Props 类测试', () => {
});
});
+ it('export - remove undefined items', () => {
+ props.import(
+ {
+ a: 1,
+ },
+ { loop: false },
+ );
+ props.setPropValue('x', undefined);
+ expect(props.export()).toEqual({
+ props: {
+ a: 1,
+ },
+ extras: {
+ loop: false,
+ },
+ });
+
+ props.setPropValue('x', 2);
+ expect(props.export()).toEqual({
+ props: {
+ a: 1,
+ x: 2,
+ },
+ extras: {
+ loop: false,
+ },
+ });
+
+ props.setPropValue('y.z', undefined);
+ expect(props.export()).toEqual({
+ props: {
+ a: 1,
+ x: 2,
+ },
+ extras: {
+ loop: false,
+ },
+ });
+
+ props.setPropValue('y.z', 2);
+ expect(props.export()).toEqual({
+ props: {
+ a: 1,
+ x: 2,
+ y: { z: 2 },
+ },
+ extras: {
+ loop: false,
+ },
+ });
+ });
+
it('import', () => {
- props.import({
- x: 1,
- y: true,
- }, { loop: false });
+ props.import(
+ {
+ x: 1,
+ y: true,
+ },
+ { loop: false },
+ );
expect(props.export()).toEqual({
props: {
x: 1,
@@ -173,19 +238,19 @@ describe('Props 类测试', () => {
expect(mockedFn).toHaveBeenCalledTimes(6);
mockedFn.mockClear();
- props.forEach(item => {
+ props.forEach((item) => {
mockedFn();
});
expect(mockedFn).toHaveBeenCalledTimes(6);
mockedFn.mockClear();
- props.map(item => {
+ props.map((item) => {
return mockedFn();
});
expect(mockedFn).toHaveBeenCalledTimes(6);
mockedFn.mockClear();
- props.filter(item => {
+ props.filter((item) => {
return mockedFn();
});
expect(mockedFn).toHaveBeenCalledTimes(6);
@@ -229,7 +294,6 @@ describe('Props 类测试', () => {
});
});
-
describe('其他函数', () => {
it('getConvertedExtraKey', () => {
expect(getConvertedExtraKey()).toBe('');
diff --git a/packages/rax-simulator-renderer/src/renderer-view.tsx b/packages/rax-simulator-renderer/src/renderer-view.tsx
index 711053e80..8444e73ef 100644
--- a/packages/rax-simulator-renderer/src/renderer-view.tsx
+++ b/packages/rax-simulator-renderer/src/renderer-view.tsx
@@ -187,7 +187,7 @@ class Renderer extends Component<{
render() {
const { documentInstance } = this.props;
- const { container } = documentInstance;
+ const { container, document } = documentInstance;
const { designMode, device } = container;
const { rendererContainer: renderer } = this.props;
this.startTime = Date.now();
@@ -209,6 +209,7 @@ class Renderer extends Component<{
onCompGetRef={(schema: any, ref: any) => {
documentInstance.mountInstance(schema.id, ref);
}}
+ documentId={document.id}
getNode={(id: string) => documentInstance.getNode(id) as any}
customCreateElement={(Component: any, props: any, children: any) => {
const { __id, ...viewProps } = props;
diff --git a/packages/react-simulator-renderer/src/renderer-view.tsx b/packages/react-simulator-renderer/src/renderer-view.tsx
index 3c0978aa3..ec1ebdf4e 100644
--- a/packages/react-simulator-renderer/src/renderer-view.tsx
+++ b/packages/react-simulator-renderer/src/renderer-view.tsx
@@ -154,7 +154,7 @@ class Renderer extends Component<{
render() {
const { documentInstance, rendererContainer: renderer } = this.props;
- const { container } = documentInstance;
+ const { container, document } = documentInstance;
const { designMode, device, locale } = container;
const messages = container.context?.utils?.i18n?.messages || {};
this.startTime = Date.now();
@@ -172,6 +172,7 @@ class Renderer extends Component<{
appHelper={container.context}
designMode={designMode}
device={device}
+ documentId={document.id}
suspended={renderer.suspended}
self={renderer.scope}
getNode={(id: string) => documentInstance.getNode(id) as Node}
diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx
index f40522a58..c6dde182f 100644
--- a/packages/renderer-core/src/hoc/leaf.tsx
+++ b/packages/renderer-core/src/hoc/leaf.tsx
@@ -50,16 +50,30 @@ enum RerenderType {
}
// 缓存 Leaf 层组件,防止重新渲染问题
-const leafComponentCache: {
+let leafComponentCaches: {
[componentName: string]: any;
} = {};
+
+let cacheDocumentId: any;
+
+function clearCaches(curDocumentId: any, {
+ __debug,
+}: any) {
+ if (cacheDocumentId === curDocumentId) {
+ return;
+ }
+ __debug(`DocumentId changed to ${curDocumentId}, clear caches!`);
+ cacheDocumentId = curDocumentId;
+ leafComponentCaches = {};
+}
+
// 缓存导致 rerender 的订阅事件
const rerenderEventCache: {
[componentId: string]: any;
} = {};
/** 部分没有渲染的 node 节点进行兜底处理 or 渲染方式没有渲染 LeafWrapper */
-function makeRerenderEvent({
+function initRerenderEvent({
schema,
__debug,
container,
@@ -98,6 +112,7 @@ function clearRerenderEvent(id: string): void {
if (!rerenderEventCache[id]) {
rerenderEventCache[id] = {
clear: true,
+ dispose: [],
};
return;
}
@@ -119,27 +134,34 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
} = baseRenderer;
const engine = baseRenderer.context.engine;
const host: BuiltinSimulatorHost = baseRenderer.props.__host;
+ const curDocumentId = baseRenderer.props?.documentId;
const getNode = baseRenderer.props?.getNode;
const container: BuiltinSimulatorHost = baseRenderer.props.__container;
const editor = host?.designer?.editor;
- const { Component } = adapter.getRuntime();
+ const { Component, forwardRef } = adapter.getRuntime();
+
+ if (curDocumentId !== cacheDocumentId) {
+ clearCaches(curDocumentId, {
+ __debug,
+ });
+ }
if (!isReactComponent(Comp)) {
console.error(`${schema.componentName} component may be has errors: `, Comp);
}
- makeRerenderEvent({
+ initRerenderEvent({
schema,
__debug,
container,
getNode,
});
- if (leafComponentCache[schema.componentName]) {
- return leafComponentCache[schema.componentName];
+ if (leafComponentCaches[schema.componentName]) {
+ return leafComponentCaches[schema.componentName];
}
- class LeafWrapper extends Component {
+ class LeafHoc extends Component {
recordInfo: {
startTime?: number | null;
type?: string;
@@ -156,7 +178,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
return;
}
const endTime = Date.now();
- const nodeCount = host.designer.currentDocument?.getNodeCount?.();
+ const nodeCount = host?.designer?.currentDocument?.getNodeCount?.();
const componentName = this.recordInfo.node?.componentName || this.leaf?.componentName || 'UnknownComponent';
editor?.emit(GlobalEvent.Node.Rerender, {
componentName,
@@ -171,18 +193,39 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
this.recordTime();
}
+ componentDidMount() {
+ this.recordTime();
+ }
+
+ get childrenMap(): any {
+ const map = new Map();
+
+ if (!this.hasChildren) {
+ return map;
+ }
+
+ this.children.forEach((d: any) => {
+ if (Array.isArray(d)) {
+ map.set(d[0].props.componentId, d);
+ return;
+ }
+ map.set(d.props.componentId, d);
+ });
+
+ return map;
+ }
+
constructor(props: IProps, context: any) {
super(props, context);
// 监听以下事件,当变化时更新自己
- clearRerenderEvent(schema.id);
+ __debug(`${schema.componentName}[${this.props.componentId}] leaf render in SimulatorRendererView`);
+ clearRerenderEvent(this.props.componentId);
this.initOnPropsChangeEvent();
this.initOnChildrenChangeEvent();
this.initOnVisibleChangeEvent();
- __debug(`${schema.componentName}[${schema.id}] leaf render in SimulatorRendererView`);
this.state = {
nodeChildren: null,
childrenInState: false,
- __tag: props.__tag,
};
}
@@ -198,17 +241,11 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
// }
componentWillReceiveProps(nextProps: any) {
- const { _leaf, __tag, children, ...rest } = nextProps;
- if (nextProps.__tag === this.state.__tag) {
- const nextProps = getProps(this.leaf?.export?.(TransformStage.Render) as types.ISchema, Comp, componentInfo);
- this.setState({
- nodeProps: {
- ...rest,
- ...nextProps,
- },
- });
+ const { _leaf } = nextProps;
+ if (nextProps.__tag === this.props.__tag) {
return null;
}
+
if (_leaf && this.leaf && _leaf !== this.leaf) {
this.disposeFunctions.forEach(fn => fn());
this.disposeFunctions = [];
@@ -218,10 +255,9 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
}
this.setState({
- nodeChildren: children,
- nodeProps: rest,
- childrenInState: true,
- __tag,
+ nodeChildren: null,
+ nodeProps: {},
+ childrenInState: false,
});
}
@@ -300,7 +336,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
// }
this.beforeRender(`${RerenderType.ChildChanged}-${type}`, node);
__debug(`${leaf} component trigger onChildrenChange event`);
- const nextChild = getChildren(leaf?.export?.(TransformStage.Render) as types.ISchema, Comp);
+ const nextChild = getChildren(leaf?.export?.(TransformStage.Render) as types.ISchema, Comp, this.childrenMap);
this.setState({
nodeChildren: nextChild,
childrenInState: true,
@@ -359,17 +395,28 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
return null;
}
+ const {
+ ref,
+ ...rest
+ } = this.props;
+
const compProps = {
- ...this.props,
+ ...rest,
...(this.state.nodeProps || {}),
children: [],
__id: this.props.componentId,
+ ref: this.props.forwardedRef,
};
return engine.createElement(Comp, compProps, this.hasChildren ? this.children : null);
}
}
+ const LeafWrapper = forwardRef((props: any, ref: any) => (
+ // @ts-ignore
+
+ ));
+
if (typeof Comp === 'object') {
const compExtraPropertyNames = Object.getOwnPropertyNames(Comp).filter(d => !compDefaultPropertyNames.includes(d));
@@ -382,7 +429,7 @@ export function leafWrapper(Comp: types.IBaseRenderer, {
LeafWrapper.displayName = (Comp as any).displayName;
- leafComponentCache[schema.componentName] = LeafWrapper;
+ leafComponentCaches[schema.componentName] = LeafWrapper;
return LeafWrapper;
}
\ No newline at end of file
diff --git a/packages/renderer-core/src/renderer/addon.tsx b/packages/renderer-core/src/renderer/addon.tsx
index cedb3e065..7720051a4 100644
--- a/packages/renderer-core/src/renderer/addon.tsx
+++ b/packages/renderer-core/src/renderer/addon.tsx
@@ -77,7 +77,7 @@ export default function addonRendererFactory() {
return '插件 schema 结构异常!';
}
- this.__debug(`render - ${__schema.fileName}`);
+ this.__debug(`${AddonRenderer.dislayName} render - ${__schema.fileName}`);
this.__generateCtx({
component: this,
});
diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx
index 87f4ad919..f234677ac 100644
--- a/packages/renderer-core/src/renderer/base.tsx
+++ b/packages/renderer-core/src/renderer/base.tsx
@@ -521,7 +521,7 @@ export default function baseRenererFactory() {
props.key = props.__id;
}
- let child: any = this.__getSchemaChildrenVirtualDom(schema, Comp);
+ let child: any = parentInfo.componentChildren || this.__getSchemaChildrenVirtualDom(schema, Comp);
const renderComp = (props: any) => engine.createElement(Comp, props, child);
// 设计模式下的特殊处理
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
@@ -580,7 +580,7 @@ export default function baseRenererFactory() {
.map((d: IComponentHoc) => d.hoc);
}
- __getSchemaChildrenVirtualDom = (schema: ISchema, Comp: any) => {
+ __getSchemaChildrenVirtualDom = (schema: ISchema, Comp: any, childrenMap?: Map) => {
let _children = this.getSchemaChildren(schema);
let children: any = [];
@@ -596,6 +596,8 @@ export default function baseRenererFactory() {
{
schema,
Comp,
+ // 有 childrenMap 情况下,children 只计算第一层,不需要遍历多层。
+ componentChildren: childrenMap?.get(_child.id)?.props.children || null,
},
);
@@ -834,11 +836,16 @@ export default function baseRenererFactory() {
componentInfo: {},
});
const { className } = data;
+ const otherProps: any = {};
const { engine } = this.context || {};
if (!engine) {
return null;
}
+ if (this._designModeIsDesign) {
+ otherProps.__tag = Math.random();
+ }
+
const child = engine.createElement(
Comp,
{
@@ -847,6 +854,7 @@ export default function baseRenererFactory() {
ref: this.__getRef,
className: classnames(getFileCssName(__schema?.fileName), className, this.props.className),
__id: __schema?.id,
+ ...otherProps,
},
this.__createDom(),
);
diff --git a/packages/renderer-core/src/renderer/block.tsx b/packages/renderer-core/src/renderer/block.tsx
index 599410c4d..d6d230c4d 100644
--- a/packages/renderer-core/src/renderer/block.tsx
+++ b/packages/renderer-core/src/renderer/block.tsx
@@ -23,7 +23,7 @@ export default function blockRendererFactory() {
return '区块 schema 结构异常!';
}
- this.__debug(`render - ${__schema.fileName}`);
+ this.__debug(`${BlockRenderer.dislayName} render - ${__schema.fileName}`);
this.__generateCtx({});
this.__render();
diff --git a/packages/renderer-core/src/renderer/component.tsx b/packages/renderer-core/src/renderer/component.tsx
index 229958f46..81b40dc32 100644
--- a/packages/renderer-core/src/renderer/component.tsx
+++ b/packages/renderer-core/src/renderer/component.tsx
@@ -23,7 +23,7 @@ export default function componentRendererFactory() {
if (this.__checkSchema(__schema)) {
return '自定义组件 schema 结构异常!';
}
- this.__debug(`render - ${__schema.fileName}`);
+ this.__debug(`${CompRenderer.dislayName} render - ${__schema.fileName}`);
this.__generateCtx({
component: this,
diff --git a/packages/renderer-core/src/renderer/page.tsx b/packages/renderer-core/src/renderer/page.tsx
index 3c7be518f..6e7f290ed 100644
--- a/packages/renderer-core/src/renderer/page.tsx
+++ b/packages/renderer-core/src/renderer/page.tsx
@@ -36,7 +36,7 @@ export default function pageRendererFactory() {
if (this.__checkSchema(__schema)) {
return '页面schema结构异常!';
}
- this.__debug(`render - ${__schema.fileName}`);
+ this.__debug(`${PageRenderer.dislayName} render - ${__schema.fileName}`);
this.__bindCustomMethods(this.props);
this.__initDataSource(this.props);
diff --git a/packages/renderer-core/src/renderer/temp.tsx b/packages/renderer-core/src/renderer/temp.tsx
index fc3e3c48d..061e561b2 100644
--- a/packages/renderer-core/src/renderer/temp.tsx
+++ b/packages/renderer-core/src/renderer/temp.tsx
@@ -48,7 +48,7 @@ export default function tempRendererFactory() {
return '下钻编辑 schema 结构异常!';
}
- this.__debug(`render - ${__schema.fileName}`);
+ this.__debug(`${TempRenderer.dislayName} render - ${__schema.fileName}`);
return this.__renderContent(this.__renderContextProvider({ __ctx }));
}
diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts
index e5e68cf3b..e1246082a 100644
--- a/packages/renderer-core/src/types/index.ts
+++ b/packages/renderer-core/src/types/index.ts
@@ -63,6 +63,7 @@ export interface IInfo {
schema: ISchema;
Comp: any;
componentInfo?: any;
+ componentChildren?: any
}
export interface JSExpression {