fix(watch): pre-flush watcher watching props should trigger before component update
fix #1763
This commit is contained in:
parent
b10bc2820a
commit
d4c17fb48b
@ -432,6 +432,46 @@ describe('api: watch', () => {
|
|||||||
expect(cb).toHaveBeenCalledTimes(1)
|
expect(cb).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #1763
|
||||||
|
it('flush: pre watcher watching props should fire before child update', async () => {
|
||||||
|
const a = ref(0)
|
||||||
|
const b = ref(0)
|
||||||
|
const calls: string[] = []
|
||||||
|
|
||||||
|
const Comp = {
|
||||||
|
props: ['a', 'b'],
|
||||||
|
setup(props: any) {
|
||||||
|
watch(
|
||||||
|
() => props.a + props.b,
|
||||||
|
() => {
|
||||||
|
calls.push('watcher')
|
||||||
|
},
|
||||||
|
{ flush: 'pre' }
|
||||||
|
)
|
||||||
|
return () => {
|
||||||
|
calls.push('render')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
render() {
|
||||||
|
return h(Comp, { a: a.value, b: b.value })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(h(App), nodeOps.createElement('div'))
|
||||||
|
expect(calls).toEqual(['render'])
|
||||||
|
|
||||||
|
// both props are updated
|
||||||
|
// should trigger pre-flush watcher first and only once
|
||||||
|
// then trigger child render
|
||||||
|
a.value++
|
||||||
|
b.value++
|
||||||
|
await nextTick()
|
||||||
|
expect(calls).toEqual(['render', 'watcher', 'render'])
|
||||||
|
})
|
||||||
|
|
||||||
it('deep', async () => {
|
it('deep', async () => {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
nested: {
|
nested: {
|
||||||
|
@ -40,7 +40,8 @@ import {
|
|||||||
queueJob,
|
queueJob,
|
||||||
queuePostFlushCb,
|
queuePostFlushCb,
|
||||||
flushPostFlushCbs,
|
flushPostFlushCbs,
|
||||||
invalidateJob
|
invalidateJob,
|
||||||
|
runPreflushJobs
|
||||||
} from './scheduler'
|
} from './scheduler'
|
||||||
import { effect, stop, ReactiveEffectOptions, isRef } from '@vue/reactivity'
|
import { effect, stop, ReactiveEffectOptions, isRef } from '@vue/reactivity'
|
||||||
import { updateProps } from './componentProps'
|
import { updateProps } from './componentProps'
|
||||||
@ -1429,6 +1430,7 @@ function baseCreateRenderer(
|
|||||||
instance.next = null
|
instance.next = null
|
||||||
updateProps(instance, nextVNode.props, prevProps, optimized)
|
updateProps(instance, nextVNode.props, prevProps, optimized)
|
||||||
updateSlots(instance, nextVNode.children)
|
updateSlots(instance, nextVNode.children)
|
||||||
|
runPreflushJobs()
|
||||||
}
|
}
|
||||||
|
|
||||||
const patchChildren: PatchChildrenFn = (
|
const patchChildren: PatchChildrenFn = (
|
||||||
|
@ -26,6 +26,7 @@ let isFlushPending = false
|
|||||||
let flushIndex = 0
|
let flushIndex = 0
|
||||||
let pendingPostFlushCbs: Function[] | null = null
|
let pendingPostFlushCbs: Function[] | null = null
|
||||||
let pendingPostFlushIndex = 0
|
let pendingPostFlushIndex = 0
|
||||||
|
let hasPendingPreFlushJobs = false
|
||||||
|
|
||||||
const RECURSION_LIMIT = 100
|
const RECURSION_LIMIT = 100
|
||||||
type CountMap = Map<SchedulerJob | Function, number>
|
type CountMap = Map<SchedulerJob | Function, number>
|
||||||
@ -47,6 +48,7 @@ export function queueJob(job: SchedulerJob) {
|
|||||||
!queue.includes(job, job.cb ? flushIndex + 1 : flushIndex)
|
!queue.includes(job, job.cb ? flushIndex + 1 : flushIndex)
|
||||||
) {
|
) {
|
||||||
queue.push(job)
|
queue.push(job)
|
||||||
|
if ((job.id as number) < 0) hasPendingPreFlushJobs = true
|
||||||
queueFlush()
|
queueFlush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,6 +60,19 @@ export function invalidateJob(job: SchedulerJob) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function runPreflushJobs() {
|
||||||
|
if (hasPendingPreFlushJobs) {
|
||||||
|
hasPendingPreFlushJobs = false
|
||||||
|
for (let job, i = queue.length - 1; i > flushIndex; i--) {
|
||||||
|
job = queue[i]
|
||||||
|
if (job && (job.id as number) < 0) {
|
||||||
|
job()
|
||||||
|
queue[i] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function queuePostFlushCb(cb: Function | Function[]) {
|
export function queuePostFlushCb(cb: Function | Function[]) {
|
||||||
if (!isArray(cb)) {
|
if (!isArray(cb)) {
|
||||||
if (
|
if (
|
||||||
|
Loading…
Reference in New Issue
Block a user