Skip to content

Commit

Permalink
feat(runtime-core): watchSyncEffect
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jul 20, 2021
1 parent 33c2fbf commit d87d059
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
47 changes: 45 additions & 2 deletions packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import {
serializeInner,
TestElement,
h,
createApp
createApp,
watchPostEffect,
watchSyncEffect
} from '@vue/runtime-test'
import {
ITERATE_KEY,
Expand All @@ -28,7 +30,6 @@ import {
Ref,
effectScope
} from '@vue/reactivity'
import { watchPostEffect } from '../src/apiWatch'

// reference: https://vue-composition-api-rfc.netlify.com/api.html#watch

Expand Down Expand Up @@ -444,6 +445,48 @@ describe('api: watch', () => {
expect(result2).toBe(true)
})

it('watchSyncEffect', async () => {
const count = ref(0)
const count2 = ref(0)

let callCount = 0
let result1
let result2
const assertion = jest.fn(count => {
callCount++
// on mount, the watcher callback should be called before DOM render
// on update, should be called before the count is updated
const expectedDOM = callCount === 1 ? `` : `${count - 1}`
result1 = serializeInner(root) === expectedDOM

// in a sync callback, state mutation on the next line should not have
// executed yet on the 2nd call, but will be on the 3rd call.
const expectedState = callCount < 3 ? 0 : 1
result2 = count2.value === expectedState
})

const Comp = {
setup() {
watchSyncEffect(() => {
assertion(count.value)
})
return () => count.value
}
}
const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(assertion).toHaveBeenCalledTimes(1)
expect(result1).toBe(true)
expect(result2).toBe(true)

count.value++
count2.value++
await nextTick()
expect(assertion).toHaveBeenCalledTimes(3)
expect(result1).toBe(true)
expect(result2).toBe(true)
})

it('should not fire on component unmount w/ flush: post', async () => {
const toggle = ref(true)
const cb = jest.fn()
Expand Down
13 changes: 13 additions & 0 deletions packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ export function watchPostEffect(
)
}

export function watchSyncEffect(
effect: WatchEffect,
options?: DebuggerOptions
) {
return doWatch(
effect,
null,
(__DEV__
? Object.assign(options || {}, { flush: 'sync' })
: { flush: 'sync' }) as WatchOptionsBase
)
}

// initial value for watchers to trigger on undefined initial values
const INITIAL_WATCHER_VALUE = {}

Expand Down
7 changes: 6 additions & 1 deletion packages/runtime-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ export {
getCurrentScope,
onScopeDispose
} from '@vue/reactivity'
export { watch, watchEffect, watchPostEffect } from './apiWatch'
export {
watch,
watchEffect,
watchPostEffect,
watchSyncEffect
} from './apiWatch'
export {
onBeforeMount,
onMounted,
Expand Down

0 comments on commit d87d059

Please sign in to comment.