Skip to content

Commit

Permalink
fix(watch): pre-flush watcher watching props should trigger before co…
Browse files Browse the repository at this point in the history
…mponent update

fix #1763
  • Loading branch information
yyx990803 committed Aug 3, 2020
1 parent b10bc28 commit d4c17fb
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 1 deletion.
40 changes: 40 additions & 0 deletions packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,46 @@ describe('api: watch', () => {
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 () => {
const state = reactive({
nested: {
Expand Down
4 changes: 3 additions & 1 deletion packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ import {
queueJob,
queuePostFlushCb,
flushPostFlushCbs,
invalidateJob
invalidateJob,
runPreflushJobs
} from './scheduler'
import { effect, stop, ReactiveEffectOptions, isRef } from '@vue/reactivity'
import { updateProps } from './componentProps'
Expand Down Expand Up @@ -1429,6 +1430,7 @@ function baseCreateRenderer(
instance.next = null
updateProps(instance, nextVNode.props, prevProps, optimized)
updateSlots(instance, nextVNode.children)
runPreflushJobs()
}

const patchChildren: PatchChildrenFn = (
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime-core/src/scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ let isFlushPending = false
let flushIndex = 0
let pendingPostFlushCbs: Function[] | null = null
let pendingPostFlushIndex = 0
let hasPendingPreFlushJobs = false

const RECURSION_LIMIT = 100
type CountMap = Map<SchedulerJob | Function, number>
Expand All @@ -47,6 +48,7 @@ export function queueJob(job: SchedulerJob) {
!queue.includes(job, job.cb ? flushIndex + 1 : flushIndex)
) {
queue.push(job)
if ((job.id as number) < 0) hasPendingPreFlushJobs = true
queueFlush()
}
}
Expand All @@ -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[]) {
if (!isArray(cb)) {
if (
Expand Down

0 comments on commit d4c17fb

Please sign in to comment.