diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 74e93c106..7678ee346 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -162,12 +162,21 @@ export class Prop implements IProp, IPropParent { return runInAction(() => { let items: IProp[] | null = null; if (this._type === 'list') { + const maps = new Map(); const data = this._value; data.forEach((item: any, idx: number) => { items = items || []; - items.push(new Prop(this, item, idx)); + let prop; + if (this._prevMaps?.has(idx.toString())) { + prop = this._prevMaps.get(idx.toString())!; + prop.setValue(item); + } else { + prop = new Prop(this, item, idx); + } + maps.set(idx.toString(), prop); + items.push(prop); }); - this._maps = null; + this._maps = maps; } else if (this._type === 'map') { const data = this._value; const maps = new Map(); @@ -377,6 +386,8 @@ export class Prop implements IProp, IPropParent { } this.dispose(); + // setValue 的时候,如果不重新建立 items,items 的 setValue 没有触发,会导致子项的响应式逻辑不能被触发 + this.setupItems(); if (oldValue !== this._value) { const propsInfo = { diff --git a/packages/designer/tests/designer/setting/setting-field.test.ts b/packages/designer/tests/designer/setting/setting-field.test.ts index 9114d2577..f79bc9876 100644 --- a/packages/designer/tests/designer/setting/setting-field.test.ts +++ b/packages/designer/tests/designer/setting/setting-field.test.ts @@ -182,5 +182,66 @@ describe('setting-field 测试', () => { expect(mockFn).toHaveBeenCalled(); }); + + it('autorun', async () => { + const settingEntry = mockNode.settingEntry as SettingTopEntry; + const arrField = settingEntry.get('columns'); + const subArrField = arrField.createField({ + name: 0, + title: 'sub', + }); + const objSubField = subArrField.createField({ + name: 'objSub', + title: 'objSub', + }); + const mockFnArrField = jest.fn(); + const mockFnSubArrField = jest.fn(); + const mockFnObjSubField = jest.fn(); + + arrField.setValue([{ objSub: "subMock0.Index.0" }]); + // 这里需要 setValue 两遍,触发 prop 的 purge 方法,使 purged 为 true,之后的 purge 方法不会正常执行,prop 才能正常缓存,autorun 才能正常执行 + // TODO: 该机制后续得研究一下,再确定是否要修改 + arrField.setValue([{ objSub: "subMock0.Index.0" }]); + + arrField.onEffect(() => { + mockFnArrField(arrField.getValue()); + }); + arrField.onEffect(() => { + mockFnSubArrField(subArrField.getValue()); + }); + arrField.onEffect(() => { + mockFnObjSubField(objSubField.getValue()); + }); + + await delayObxTick(); + + expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.0'); + expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: "subMock0.Index.0" }); + expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: "subMock0.Index.0" }]); + + arrField.setValue([{ objSub: "subMock0.Index.1" }]); + + await delayObxTick(); + + expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.1'); + expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: "subMock0.Index.1" }); + expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: "subMock0.Index.1" }]); + + subArrField.setValue({ objSub: "subMock0.Index.2" }); + + await delayObxTick(); + + expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.2'); + expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: "subMock0.Index.2" }); + expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: "subMock0.Index.2" }]); + + objSubField.setValue('subMock0.Index.3'); + + await delayObxTick(); + + expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.3'); + expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: "subMock0.Index.3" }); + expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: "subMock0.Index.3" }]); + }) }); }); diff --git a/packages/designer/tests/fixtures/window.ts b/packages/designer/tests/fixtures/window.ts index 6f3e03a88..c57fcb686 100644 --- a/packages/designer/tests/fixtures/window.ts +++ b/packages/designer/tests/fixtures/window.ts @@ -22,7 +22,7 @@ window.console.warn = () => {}; const originalLog = window.console.log; window.console.log = (...args) => { // suppress boring warnings - if (args[0].includes('@babel/plugin-proposal-private-property-in-object')) return; + if (args[0]?.includes && args[0].includes('@babel/plugin-proposal-private-property-in-object')) return; originalLog.apply(window.console, args); }; window.React = window.React || {};