diff --git a/packages/core/src/__tests__/array.spec.ts b/packages/core/src/__tests__/array.spec.ts index 158284e496d..08ccacf8ccc 100644 --- a/packages/core/src/__tests__/array.spec.ts +++ b/packages/core/src/__tests__/array.spec.ts @@ -514,6 +514,7 @@ test('array field remove memo leak', async () => { expect(initialValuesChange).toBeCalledTimes(0) }) +// add sandbox https://codesandbox.io/p/devbox/lingering-violet-jwr565 test('nest array remove', async () => { const form = attach(createForm()) @@ -588,11 +589,84 @@ test('nest array remove', async () => { expect(form.fields['metrics.0.content.0.attr']).not.toBeUndefined() await metrics.remove(1) expect(form.fields['metrics.0.content.0.attr']).not.toBeUndefined() + // TODO!! 测试不通过 expect( form.initialValues.metrics?.[1]?.content?.[0]?.attr ).not.toBeUndefined() }) + +test('nest array remove for #4024', () => { + const form = attach(createForm()) + const arr1 = attach( + form.createArrayField({ + name: 'aa', + initialValue: [{}], + }) + ) + + attach( + form.createArrayField({ + name: 'bb', + basePath: 'aa.0', + initialValue: [{}], + }) + ) + + attach( + form.createField({ + name: 'cc', + basePath: 'aa.0.bb.0', + initialValue: true, + }) + ) + + expect(form.initialValues).toEqual({ + aa: [{ bb: [{ cc: true }] }], + }) + + // 模拟两次 antd/ArrayBase.Addation 点击 + attach( + form.createField({ + name: 'cc', + basePath: 'aa.0.bb.1', + initialValue: true, + }) + ) + attach( + form.createField({ + name: 'cc', + basePath: 'aa.0.bb.2', + initialValue: true, + }) + ) + // 符合 formily DevTools 表现 + expect(form.initialValues).toEqual({ + aa: [{ bb: [{ cc: true }, { cc: true }, { cc: true }] }], + }) + // 模拟 antd/ArrayBase.Remove 点击 + arr1.remove(0) + + // 模拟一次外部数组点击 antd/ArrayBase.Addation 点击 + attach( + form.createArrayField({ + name: 'bb', + basePath: 'aa.0', + initialValue: [{}], + }) + ) + attach( + form.createField({ + name: 'cc', + basePath: 'aa.0.bb.0', + initialValue: true, + }) + ) + expect(form.initialValues).toEqual({ + aa: [{ bb: [{ cc: true }] }], + }) +}) + test('indexes: nest path need exclude incomplete number', () => { const form = attach(createForm()) diff --git a/packages/core/src/__tests__/form.spec.ts b/packages/core/src/__tests__/form.spec.ts index 1416d94cb07..63ed4a8290e 100644 --- a/packages/core/src/__tests__/form.spec.ts +++ b/packages/core/src/__tests__/form.spec.ts @@ -1156,77 +1156,6 @@ test('form lifecycle can be triggered after call form.setXXX', () => { expect(valuesTriggerNum).toEqual(6) }) -test('reference initialValue should forceClear in destory, fix 4024', () => { - const form = attach(createForm()) - const arr1 = attach( - form.createArrayField({ - name: 'aa', - initialValue: [{}], - }) - ) - - attach( - form.createArrayField({ - name: 'bb', - basePath: 'aa.0', - initialValue: [{}], - }) - ) - - attach( - form.createField({ - name: 'cc', - basePath: 'aa.0.bb.0', - initialValue: true, - }) - ) - - expect(form.initialValues).toEqual({ - aa: [{ bb: [{ cc: true }] }], - }) - - // 模拟两次 antd/ArrayBase.Addation 点击 - attach( - form.createField({ - name: 'cc', - basePath: 'aa.0.bb.1', - initialValue: true, - }) - ) - attach( - form.createField({ - name: 'cc', - basePath: 'aa.0.bb.2', - initialValue: true, - }) - ) - // 符合 formily DevTools 表现 - expect(form.initialValues).toEqual({ - aa: [{ bb: [{ cc: true }, { cc: true }, { cc: true }] }], - }) - // 模拟 antd/ArrayBase.Remove 点击 - arr1.remove(0) - - // 模拟一次外部数组点击 antd/ArrayBase.Addation 点击 - attach( - form.createArrayField({ - name: 'bb', - basePath: 'aa.0', - initialValue: [{}], - }) - ) - attach( - form.createField({ - name: 'cc', - basePath: 'aa.0.bb.0', - initialValue: true, - }) - ) - expect(form.initialValues).toEqual({ - aa: [{ bb: [{ cc: true }] }], - }) -}) - test('form values change with array field(default value)', async () => { const handler = jest.fn() const form = attach( diff --git a/packages/core/src/shared/internals.ts b/packages/core/src/shared/internals.ts index 62100e4e469..52eaf6b86da 100644 --- a/packages/core/src/shared/internals.ts +++ b/packages/core/src/shared/internals.ts @@ -154,8 +154,7 @@ export const patchFieldStates = ( ) => { patches.forEach(({ type, address, oldAddress, payload }) => { if (type === 'remove') { - const forceClear = isUndef(target?.initialValue) - destroy(target, address, forceClear) + destroy(target, address, false) } else if (type === 'update') { if (payload) { target[address] = payload @@ -177,11 +176,17 @@ export const destroy = ( ) => { const field = target[address] field?.dispose() - if (isDataField(field) && forceClear) { + if (isDataField(field)) { const form = field.form const path = field.path - form.deleteValuesIn(path) - form.deleteInitialValuesIn(path) + if (forceClear) { + form.deleteValuesIn(path) + } + // 在 schema 上有定义 initialValue (JSX prop name: default) + const shouldClearInitial = forceClear || !isUndef(field.props.initialValue); + if (shouldClearInitial) { + form.deleteInitialValuesIn(path) + } } delete target[address] }