Skip to content

Commit

Permalink
fix(reactive): fix reaction scheduler prevent setState rerender
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang committed Dec 10, 2021
1 parent e2dfc0b commit 01078d9
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 17 deletions.
18 changes: 6 additions & 12 deletions packages/core/src/models/Field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,7 @@ import {
ValidatorTriggerType,
parseValidatorDescriptions,
} from '@formily/validator'
import {
define,
observable,
reaction,
batch,
toJS,
action,
} from '@formily/reactive'
import { define, observable, batch, toJS, action } from '@formily/reactive'
import {
JSXComponent,
LifeCycleTypes,
Expand Down Expand Up @@ -56,6 +49,7 @@ import {
initializeStart,
initializeEnd,
createChildrenFeedbackFilter,
createReaction,
} from '../shared/internals'
import { Form } from './Form'
import { BaseField } from './BaseField'
Expand Down Expand Up @@ -228,7 +222,7 @@ export class Field<
protected makeReactive() {
if (this.designable) return
this.disposers.push(
reaction(
createReaction(
() => this.value,
(value) => {
this.notify(LifeCycleTypes.ON_FIELD_VALUE_CHANGE)
Expand All @@ -237,13 +231,13 @@ export class Field<
}
}
),
reaction(
createReaction(
() => this.initialValue,
() => {
this.notify(LifeCycleTypes.ON_FIELD_INITIAL_VALUE_CHANGE)
}
),
reaction(
createReaction(
() => this.display,
(display) => {
const value = this.value
Expand All @@ -266,7 +260,7 @@ export class Field<
}
}
),
reaction(
createReaction(
() => this.pattern,
(pattern) => {
if (pattern !== 'editable') {
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/shared/internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
toJS,
isObservable,
DataChange,
reaction,
untracked,
} from '@formily/reactive'
import { Field, ArrayField, Form, ObjectField } from '../models'
import {
Expand Down Expand Up @@ -1031,6 +1033,13 @@ export const createReactions = (field: GeneralField) => {
})
}

export const createReaction = <T>(
tracker: () => T,
scheduler?: (value: T) => void
) => {
return reaction(tracker, untracked.bound(scheduler))
}

export const initializeStart = () => {
GlobalState.initializing = true
}
Expand Down
53 changes: 52 additions & 1 deletion packages/reactive/src/__tests__/batch.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { observable, batch, autorun } from '..'
import { observable, batch, autorun, reaction } from '..'
import { define } from '../model'

describe('normal batch', () => {
Expand Down Expand Up @@ -539,3 +539,54 @@ describe('batch endpoint', () => {
expect(tokens).toEqual(['endpoint'])
})
})

test('reaction collect in batch valid', () => {
const obs = observable({
aa: 11,
bb: 22,
cc: 33,
})
reaction(
() => obs.aa,
() => {
void obs.cc
}
)
const fn = jest.fn()

autorun(() => {
batch.scope(() => {
obs.aa = obs.bb
})
fn()
})

obs.bb = 44
expect(fn).toBeCalledTimes(2)
})

test('reaction collect in batch invalid', () => {
const obs = observable({
aa: 11,
bb: 22,
cc: 33,
})
reaction(
() => obs.aa,
() => {
void obs.cc
}
)
const fn = jest.fn()

autorun(() => {
batch.scope(() => {
obs.aa = obs.bb
})
fn()
})

obs.bb = 44
obs.cc = 55
expect(fn).toBeCalledTimes(3)
})
5 changes: 1 addition & 4 deletions packages/reactive/src/autorun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {
releaseBindingReactions,
disposeEffects,
hasDepsChange,
untrackStart,
untrackEnd,
} from './reaction'
import { isFn } from './checkers'
import { ReactionStack } from './environment'
Expand Down Expand Up @@ -119,12 +117,11 @@ export const reaction = <T>(

const fireAction = () => {
try {
untrackStart()
//如果untrack的话,会导致用户如果在scheduler里同步调用setState影响下次React渲染的依赖收集
batchStart()
if (isFn(subscriber)) subscriber(value.currentValue, value.oldValue)
} finally {
batchEnd()
untrackEnd()
}
}

Expand Down

0 comments on commit 01078d9

Please sign in to comment.