diff --git a/packages/core/src/__tests__/field.spec.ts b/packages/core/src/__tests__/field.spec.ts index 5b0688963da..54997c2fb37 100644 --- a/packages/core/src/__tests__/field.spec.ts +++ b/packages/core/src/__tests__/field.spec.ts @@ -1,4 +1,4 @@ -import { autorun, batch } from '@formily/reactive' +import { autorun, batch, observable } from '@formily/reactive' import { createForm, onFieldReact, isField } from '../' import { DataField } from '../types' import { attach, sleep } from './shared' @@ -2109,18 +2109,17 @@ test('destroy field need auto remove initialValues', () => { }) test('validateFirst', async () => { - const form = attach(createForm({ - validateFirst: false - })) + const form = attach( + createForm({ + validateFirst: false, + }) + ) const aaValidate = jest.fn(() => 'aaError') const aa = attach( form.createField({ name: 'aa', validateFirst: true, - validator: [ - aaValidate, - aaValidate, - ] + validator: [aaValidate, aaValidate], }) ) await aa.onInput('aa') @@ -2128,10 +2127,7 @@ test('validateFirst', async () => { const bb = attach( form.createField({ name: 'bb', - validator: [ - bbValidate, - bbValidate, - ], + validator: [bbValidate, bbValidate], validateFirst: false, }) ) @@ -2140,10 +2136,7 @@ test('validateFirst', async () => { const cc = attach( form.createField({ name: 'cc', - validator: [ - ccValidate, - ccValidate, - ], + validator: [ccValidate, ccValidate], }) ) await cc.onInput('cc') @@ -2152,3 +2145,22 @@ test('validateFirst', async () => { expect(bbValidate).toBeCalledTimes(2) expect(ccValidate).toBeCalledTimes(2) }) + +test('reactions should not be triggered when field destroyed', () => { + const form = attach(createForm()) + const handler = jest.fn() + const obs = observable({ bb: 123 }) + const aa = attach( + form.createField({ + name: 'aa', + initialValue: 'test', + reactions() { + handler(obs.bb) + }, + }) + ) + obs.bb = 321 + aa.destroy() + obs.bb = 111 + expect(handler).toBeCalledTimes(2) +}) diff --git a/packages/core/src/models/BaseField.ts b/packages/core/src/models/BaseField.ts index a2f0799a504..b3727b4e1eb 100644 --- a/packages/core/src/models/BaseField.ts +++ b/packages/core/src/models/BaseField.ts @@ -124,6 +124,10 @@ export class BaseField { return this.display === 'visible' } + get destroyed() { + return !this.form.fields[this.address.toString()] + } + set hidden(hidden: boolean) { if (!isValid(hidden)) return if (hidden) { diff --git a/packages/core/src/shared/internals.ts b/packages/core/src/shared/internals.ts index d5321b121ad..3c464d947ed 100644 --- a/packages/core/src/shared/internals.ts +++ b/packages/core/src/shared/internals.ts @@ -1063,7 +1063,14 @@ export const createReactions = (field: GeneralField) => { field.form.addEffects(field, () => { reactions.forEach((reaction) => { if (isFn(reaction)) { - field.disposers.push(autorun(batch.scope.bound(() => reaction(field)))) + field.disposers.push( + autorun( + batch.scope.bound(() => { + if (field.destroyed) return + reaction(field) + }) + ) + ) } }) })