fix(reactivity): ensure computed always expose value
fix #3099 Also changes the original fix for #910 by moving the fix from reactivity to the scheduler
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { effect, stop } from '@vue/reactivity'
|
||||
import {
|
||||
queueJob,
|
||||
nextTick,
|
||||
@@ -568,4 +569,27 @@ describe('scheduler', () => {
|
||||
await nextTick()
|
||||
expect(count).toBe(1)
|
||||
})
|
||||
|
||||
// #910
|
||||
test('should not run stopped reactive effects', async () => {
|
||||
const spy = jest.fn()
|
||||
|
||||
// simulate parent component that toggles child
|
||||
const job1 = () => {
|
||||
stop(job2)
|
||||
}
|
||||
job1.id = 0 // need the id to ensure job1 is sorted before job2
|
||||
|
||||
// simulate child that's triggered by the same reactive change that
|
||||
// triggers its toggle
|
||||
const job2 = effect(() => spy())
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
|
||||
queueJob(job1)
|
||||
queueJob(job2)
|
||||
await nextTick()
|
||||
|
||||
// should not be called again
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,27 +3,14 @@ import { isArray } from '@vue/shared'
|
||||
import { ComponentPublicInstance } from './componentPublicInstance'
|
||||
import { ComponentInternalInstance, getComponentName } from './component'
|
||||
import { warn } from './warning'
|
||||
import { ReactiveEffect } from '@vue/reactivity'
|
||||
|
||||
export interface SchedulerJob {
|
||||
(): void
|
||||
export interface SchedulerJob extends Function, Partial<ReactiveEffect> {
|
||||
/**
|
||||
* unique job id, only present on raw effects, e.g. component render effect
|
||||
* Attached by renderer.ts when setting up a component's render effect
|
||||
* Used to obtain component information when reporting max recursive updates.
|
||||
* dev only.
|
||||
*/
|
||||
id?: number
|
||||
/**
|
||||
* Indicates whether the job is allowed to recursively trigger itself.
|
||||
* By default, a job cannot trigger itself because some built-in method calls,
|
||||
* e.g. Array.prototype.push actually performs reads as well (#1740) which
|
||||
* can lead to confusing infinite loops.
|
||||
* The allowed cases are component update functions and watch callbacks.
|
||||
* Component update functions may update child component props, which in turn
|
||||
* trigger flush: "pre" watch callbacks that mutates state that the parent
|
||||
* relies on (#1801). Watch callbacks doesn't track its dependencies so if it
|
||||
* triggers itself again, it's likely intentional and it is the user's
|
||||
* responsibility to perform recursive state mutation that eventually
|
||||
* stabilizes (#1727).
|
||||
*/
|
||||
allowRecurse?: boolean
|
||||
ownerInstance?: ComponentInternalInstance
|
||||
}
|
||||
|
||||
@@ -243,7 +230,7 @@ function flushJobs(seen?: CountMap) {
|
||||
try {
|
||||
for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {
|
||||
const job = queue[flushIndex]
|
||||
if (job) {
|
||||
if (job && job.active !== false) {
|
||||
if (__DEV__ && checkRecursiveUpdates(seen!, job)) {
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user