diff --git a/src/apis/watch.ts b/src/apis/watch.ts index ba431af5..8fe0c5af 100644 --- a/src/apis/watch.ts +++ b/src/apis/watch.ts @@ -1,6 +1,6 @@ import { ComponentInstance } from '../component'; import { Ref, isRef } from '../reactivity'; -import { assert, logError, noopFn } from '../utils'; +import { assert, logError, noopFn, warn } from '../utils'; import { defineComponentInstance } from '../helper'; import { getCurrentVM, getCurrentVue } from '../runtimeContext'; import { WatcherPreFlushQueueKey, WatcherPostFlushQueueKey } from '../symbols'; @@ -54,6 +54,30 @@ function installWatchEnv(vm: any) { vm.$on('hook:updated', flushPostQueue); } +function getWatcherOption(options?: Partial): WatcherOption { + return { + ...{ + lazy: false, + deep: false, + flush: 'post', + }, + ...options, + }; +} + +function getWatcherVM() { + let vm = getCurrentVM(); + if (!vm) { + if (!fallbackVM) { + fallbackVM = defineComponentInstance(getCurrentVue()); + } + vm = fallbackVM; + } else if (!hasWatchEnv(vm)) { + installWatchEnv(vm); + } + return vm; +} + function flushQueue(vm: any, key: any) { const queue = vm[key]; for (let index = 0; index < queue.length; index++) { @@ -222,6 +246,15 @@ function createWatcher( }; } +export function watchEffect( + effect: SimpleEffect, + options?: Omit, 'lazy'> +): StopHandle { + const opts = getWatcherOption(options); + const vm = getWatcherVM(); + return createWatcher(vm, effect, null, opts); +} + export function watch( source: SimpleEffect, options?: Omit, 'lazy'> @@ -247,27 +280,19 @@ export function watch( callback = cb as WatcherCallBack; } else { // effect watch + if (process.env.NODE_ENV !== 'production') { + warn( + `\`watch(fn, options?)\` signature has been moved to a separate API. ` + + `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + + `supports \`watch(source, cb, options?) signature.` + ); + } options = cb as Partial; callback = null; } - const opts: WatcherOption = { - ...{ - lazy: false, - deep: false, - flush: 'post', - }, - ...options, - }; - let vm = getCurrentVM(); - if (!vm) { - if (!fallbackVM) { - fallbackVM = defineComponentInstance(getCurrentVue()); - } - vm = fallbackVM; - } else if (!hasWatchEnv(vm)) { - installWatchEnv(vm); - } + const opts = getWatcherOption(options); + const vm = getWatcherVM(); return createWatcher(vm, source, callback, opts); } diff --git a/test/apis/watch.spec.js b/test/apis/watch.spec.js index 696edc1e..cbe3f439 100644 --- a/test/apis/watch.spec.js +++ b/test/apis/watch.spec.js @@ -1,5 +1,5 @@ const Vue = require('vue/dist/vue.common.js'); -const { ref, reactive, watch } = require('../../src'); +const { ref, reactive, watch, watchEffect } = require('../../src'); describe('api/watch', () => { const anyFn = expect.any(Function); @@ -298,11 +298,11 @@ describe('api/watch', () => { const x = ref(0); // prettier-ignore - watch(() => { void x.value; result.push('sync getter'); }, { flush: 'sync' }); + watchEffect(() => { void x.value; result.push('sync effect'); }, { flush: 'sync' }); // prettier-ignore - watch(() => { void x.value; result.push('pre getter'); }, { flush: 'pre' }); + watchEffect(() => { void x.value; result.push('pre effect'); }, { flush: 'pre' }); // prettier-ignore - watch(() => { void x.value; result.push('post getter'); }, { flush: 'post' }); + watchEffect(() => { void x.value; result.push('post effect'); }, { flush: 'post' }); // prettier-ignore watch(x, () => { result.push('sync callback') }, { flush: 'sync' }) @@ -321,11 +321,11 @@ describe('api/watch', () => { }, template: `
{{x}}
`, }).$mount(); - expect(result).toEqual(['sync getter', 'sync callback', 'pre callback', 'post callback']); + expect(result).toEqual(['sync effect', 'sync callback', 'pre callback', 'post callback']); result.length = 0; waitForUpdate(() => { - expect(result).toEqual(['pre getter', 'post getter']); + expect(result).toEqual(['pre effect', 'post effect']); result.length = 0; vm.inc(); @@ -333,12 +333,12 @@ describe('api/watch', () => { .then(() => { expect(result).toEqual([ 'before inc', - 'sync getter', + 'sync effect', 'sync callback', 'after inc', - 'pre getter', + 'pre effect', 'pre callback', - 'post getter', + 'post effect', 'post callback', ]); }) @@ -352,7 +352,7 @@ describe('api/watch', () => { const vm = new Vue({ setup() { const count = ref(0); - watch(_onCleanup => { + watchEffect(_onCleanup => { onCleanup = _onCleanup; spy(count.value); renderedText = vm.$el.textContent; @@ -384,7 +384,7 @@ describe('api/watch', () => { const vm = new Vue({ setup() { const count = ref(0); - watch( + watchEffect( () => { spy(count.value); }, @@ -563,7 +563,7 @@ describe('api/watch', () => { it('simple effect', done => { const obj = reactive({ a: 1 }); - watch(() => spy(obj.a)); + watchEffect(() => spy(obj.a)); expect(spy).not.toHaveBeenCalled(); waitForUpdate(() => { expect(spy).toBeCalledTimes(1); @@ -596,10 +596,10 @@ describe('api/watch', () => { return p; } - it('work with (single getter)', done => { + it('work with effect', done => { const id = ref(1); const promises = []; - watch(onCleanup => { + watchEffect(onCleanup => { const val = getAsyncValue(id.value); promises.push(val); onCleanup(() => { @@ -617,10 +617,10 @@ describe('api/watch', () => { .then(done); }); - it('run cleanup when watch stops (single getter)', done => { + it('run cleanup when watch stops (effect)', done => { const spy = jest.fn(); const cleanup = jest.fn(); - const stop = watch(onCleanup => { + const stop = watchEffect(onCleanup => { spy(); onCleanup(cleanup); }); @@ -651,7 +651,7 @@ describe('api/watch', () => { it('should not collect reactive in onCleanup', done => { const ref1 = ref(1); const ref2 = ref(1); - watch(onCleanup => { + watchEffect(onCleanup => { spy(ref1.value); onCleanup(() => { ref2.value = ref2.value + 1; diff --git a/test/templateRefs.spec.js b/test/templateRefs.spec.js index 27373a22..260e9d4d 100644 --- a/test/templateRefs.spec.js +++ b/test/templateRefs.spec.js @@ -1,5 +1,5 @@ const Vue = require('vue/dist/vue.common.js'); -const { ref, watch, createElement: h } = require('../src'); +const { ref, watchEffect, createElement: h } = require('../src'); describe('ref', () => { it('should work', done => { @@ -7,7 +7,7 @@ describe('ref', () => { const vm = new Vue({ setup() { const ref1 = ref(null); - watch(() => { + watchEffect(() => { dummy = ref1.value; }); @@ -35,7 +35,7 @@ describe('ref', () => { setup() { const ref1 = ref(null); const ref2 = ref(null); - watch(() => { + watchEffect(() => { dummy1 = ref1.value; dummy2 = ref2.value; });