From a32269a6a4153c357ae4007788431ec11fd2c288 Mon Sep 17 00:00:00 2001 From: 2betop <2698393+2betop@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:16:23 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20store=20=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=B8=8A=E4=B8=8B=E5=B1=82=E5=90=8C=E6=AD=A5=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/amis-core/src/WithStore.tsx | 2 +- packages/amis-core/src/store/iRenderer.ts | 14 ++- .../amis/__tests__/renderers/CRUD.test.tsx | 112 ++++++++++++++++++ .../stores/__snapshots__/service.test.ts.snap | 5 + packages/amis/src/renderers/Cards.tsx | 6 +- packages/amis/src/renderers/List.tsx | 6 +- packages/amis/src/renderers/Table/index.tsx | 6 +- 7 files changed, 140 insertions(+), 11 deletions(-) diff --git a/packages/amis-core/src/WithStore.tsx b/packages/amis-core/src/WithStore.tsx index 36cadba89..6fb8d96db 100644 --- a/packages/amis-core/src/WithStore.tsx +++ b/packages/amis-core/src/WithStore.tsx @@ -298,7 +298,7 @@ export function HocStoreFactory(renderer: { props.store?.storeType === 'ComboStore' ? undefined : syncDataFromSuper( - {...store.data, ...props.data}, + {...store.pristineDiff, ...props.data}, (props.data as any).__super, (prevProps.data as any).__super, store, diff --git a/packages/amis-core/src/store/iRenderer.ts b/packages/amis-core/src/store/iRenderer.ts index 9933ae5c6..2d920734c 100644 --- a/packages/amis-core/src/store/iRenderer.ts +++ b/packages/amis-core/src/store/iRenderer.ts @@ -25,7 +25,8 @@ export const iRendererStore = StoreNode.named('iRendererStore') data: types.optional(types.frozen(), {}), initedAt: 0, // 初始 init 的时刻 updatedAt: 0, // 从服务端更新时刻 - pristine: types.optional(types.frozen(), {}), + pristine: types.optional(types.frozen(), {}), // pristine 的数据可能会被表单项的默认值,form 的 initApi 等修改 + upStreamData: types.optional(types.frozen(), {}), // 最原始的数据,只有由上游同步下来时才更新。用来判断是否变化过 action: types.optional(types.frozen(), undefined), dialogOpen: false, dialogData: types.optional(types.frozen(), undefined), @@ -39,6 +40,16 @@ export const iRendererStore = StoreNode.named('iRendererStore') getPristineValueByName(name: string) { return getVariable(self.pristine, name, false); + }, + + get pristineDiff() { + const data: any = {}; + Object.keys(self.pristine).forEach(key => { + if (self.pristine[key] !== self.upStreamData[key]) { + data[key] = self.pristine[key]; + } + }); + return data; } })) .actions(self => { @@ -63,6 +74,7 @@ export const iRendererStore = StoreNode.named('iRendererStore') !skipSetPristine && (self.pristine = data); self.data = data; + self.upStreamData = data; }, reset() { diff --git a/packages/amis/__tests__/renderers/CRUD.test.tsx b/packages/amis/__tests__/renderers/CRUD.test.tsx index 48ef57ea2..cedf6f185 100644 --- a/packages/amis/__tests__/renderers/CRUD.test.tsx +++ b/packages/amis/__tests__/renderers/CRUD.test.tsx @@ -1784,3 +1784,115 @@ test('23. Nested CRUD change to normal CRUD', async () => { const newSpace = container.querySelectorAll('.cxd-Table-expandSpace'); expect(newSpace.length).toEqual(0); }); + +// CRUD 列中存在一列 List 组件,List 是带 store 的,crud 的行数据发生切换时, +// 如果 list 关联的数组,从有有成员变成 undefined 时,会出现 List 的数据不更新的问题。 +// 原因是 withStore 里面同步逻辑有问题,保留了原来的 store.data +test('25. CRUD Table Cell sync data to store', async () => { + const {container} = render( + amisRender({ + type: 'page', + id: 'page', + data: { + source: [ + { + engine: 'Trident', + browser: 'Internet Explorer 5.0', + platform: 'Win 95+', + version: '5', + grade: 'C', + id: '1-1', + list: [{id: '1-1-1', name: '1-1-1'}] + }, + { + engine: 'Trident', + browser: 'Internet Explorer 5.0', + platform: 'Win 95+', + version: '5', + grade: 'C', + id: '5' + } + ] + }, + body: [ + { + type: 'button', + label: '切换数据源', + onEvent: { + click: { + actions: [ + { + actionType: 'setValue', + componentId: 'page', + args: { + value: { + source: [ + { + engine: 'Trident', + browser: 'Internet Explorer 4.0', + platform: 'Win 95+', + version: '4', + grade: 'X', + id: '3' + }, + { + engine: 'Trident', + browser: 'Internet Explorer 4.0', + platform: 'Win 95+', + version: '4', + grade: 'X', + id: '4' + } + ] + } + } + } + ] + } + } + }, + { + type: 'crud', + name: 'crud', + syncLocation: false, + source: '${source}', + draggable: true, + columns: [ + { + name: 'id', + label: 'ID' + }, + { + name: 'engine', + label: 'Rendering engine' + }, + { + name: 'list', + label: 'List', + type: 'list', + source: '${list}', + listItem: { + title: '${id}-${name}' + } + } + ] + } + ] + }) + ); + + await wait(300); + + const button = container.querySelectorAll('.cxd-Button')[0]; + + // 刚开始存在 list 字段,所以是 1 + const listDoms = container.querySelectorAll('.cxd-ListItem-title'); + expect(listDoms.length).toEqual(1); + + fireEvent.click(button); + await wait(300); + + // 切换后 list 字段是 undefined 了,所以应该不显示了 + const listDoms2 = container.querySelectorAll('.cxd-ListItem-title'); + expect(listDoms2.length).toEqual(0); +}); diff --git a/packages/amis/__tests__/stores/__snapshots__/service.test.ts.snap b/packages/amis/__tests__/stores/__snapshots__/service.test.ts.snap index e4c1fc46f..055ff938d 100644 --- a/packages/amis/__tests__/stores/__snapshots__/service.test.ts.snap +++ b/packages/amis/__tests__/stores/__snapshots__/service.test.ts.snap @@ -26,6 +26,7 @@ exports[`store:ServiceStore 1`] = ` "schema": null, "schemaKey": "", "storeType": "ServiceStore", + "upStreamData": {}, "updatedAt": 0, } `; @@ -57,6 +58,7 @@ exports[`store:ServiceStore fetchInitData failed 1`] = ` "schema": null, "schemaKey": "", "storeType": "ServiceStore", + "upStreamData": {}, "updatedAt": 0, }, { @@ -84,6 +86,7 @@ exports[`store:ServiceStore fetchInitData failed 1`] = ` "schema": null, "schemaKey": "", "storeType": "ServiceStore", + "upStreamData": {}, "updatedAt": 0, }, ] @@ -116,6 +119,7 @@ exports[`store:ServiceStore fetchInitData success 1`] = ` "schema": null, "schemaKey": "", "storeType": "ServiceStore", + "upStreamData": {}, }, { "action": undefined, @@ -148,6 +152,7 @@ exports[`store:ServiceStore fetchInitData success 1`] = ` "schema": null, "schemaKey": "", "storeType": "ServiceStore", + "upStreamData": {}, }, ] `; diff --git a/packages/amis/src/renderers/Cards.tsx b/packages/amis/src/renderers/Cards.tsx index be0d5cebd..6f6a47291 100644 --- a/packages/amis/src/renderers/Cards.tsx +++ b/packages/amis/src/renderers/Cards.tsx @@ -290,10 +290,10 @@ export default class Cards extends React.Component { ? resolveVariableAndFilter(source, prevProps.data, '| raw') : null; - if (prev && prev === resolved) { + if (prev === resolved) { updateItems = false; - } else if (Array.isArray(resolved)) { - items = resolved; + } else { + items = Array.isArray(resolved) ? resolved : []; updateItems = true; } } diff --git a/packages/amis/src/renderers/List.tsx b/packages/amis/src/renderers/List.tsx index 3a1360976..9580e21de 100644 --- a/packages/amis/src/renderers/List.tsx +++ b/packages/amis/src/renderers/List.tsx @@ -373,10 +373,10 @@ export default class List extends React.Component { ? resolveVariableAndFilter(source, prevProps.data, '| raw') : null; - if (prev && prev === resolved) { + if (prev === resolved) { updateItems = false; - } else if (Array.isArray(resolved)) { - items = resolved; + } else { + items = Array.isArray(resolved) ? resolved : []; updateItems = true; } } diff --git a/packages/amis/src/renderers/Table/index.tsx b/packages/amis/src/renderers/Table/index.tsx index 838375904..b85f4afe7 100644 --- a/packages/amis/src/renderers/Table/index.tsx +++ b/packages/amis/src/renderers/Table/index.tsx @@ -710,11 +710,11 @@ export default class Table extends React.Component { ? resolveVariableAndFilter(source, prevProps.data, '| raw') : null; - if (prev && prev === resolved) { + if (prev === resolved) { updateRows = false; - } else if (Array.isArray(resolved)) { + } else { updateRows = true; - rows = resolved; + rows = Array.isArray(resolved) ? resolved : []; } }