Skip to content

Commit 795dc17

Browse files
feat(apis): add watchEffect API (#275)
1 parent e1491f2 commit 795dc17

File tree

3 files changed

+63
-38
lines changed

3 files changed

+63
-38
lines changed

src/apis/watch.ts

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ComponentInstance } from '../component';
22
import { Ref, isRef } from '../reactivity';
3-
import { assert, logError, noopFn } from '../utils';
3+
import { assert, logError, noopFn, warn } from '../utils';
44
import { defineComponentInstance } from '../helper';
55
import { getCurrentVM, getCurrentVue } from '../runtimeContext';
66
import { WatcherPreFlushQueueKey, WatcherPostFlushQueueKey } from '../symbols';
@@ -54,6 +54,30 @@ function installWatchEnv(vm: any) {
5454
vm.$on('hook:updated', flushPostQueue);
5555
}
5656

57+
function getWatcherOption(options?: Partial<WatcherOption>): WatcherOption {
58+
return {
59+
...{
60+
lazy: false,
61+
deep: false,
62+
flush: 'post',
63+
},
64+
...options,
65+
};
66+
}
67+
68+
function getWatcherVM() {
69+
let vm = getCurrentVM();
70+
if (!vm) {
71+
if (!fallbackVM) {
72+
fallbackVM = defineComponentInstance(getCurrentVue());
73+
}
74+
vm = fallbackVM;
75+
} else if (!hasWatchEnv(vm)) {
76+
installWatchEnv(vm);
77+
}
78+
return vm;
79+
}
80+
5781
function flushQueue(vm: any, key: any) {
5882
const queue = vm[key];
5983
for (let index = 0; index < queue.length; index++) {
@@ -222,6 +246,15 @@ function createWatcher(
222246
};
223247
}
224248

249+
export function watchEffect(
250+
effect: SimpleEffect,
251+
options?: Omit<Partial<WatcherOption>, 'lazy'>
252+
): StopHandle {
253+
const opts = getWatcherOption(options);
254+
const vm = getWatcherVM();
255+
return createWatcher(vm, effect, null, opts);
256+
}
257+
225258
export function watch<T = any>(
226259
source: SimpleEffect,
227260
options?: Omit<Partial<WatcherOption>, 'lazy'>
@@ -247,27 +280,19 @@ export function watch(
247280
callback = cb as WatcherCallBack<unknown>;
248281
} else {
249282
// effect watch
283+
if (process.env.NODE_ENV !== 'production') {
284+
warn(
285+
`\`watch(fn, options?)\` signature has been moved to a separate API. ` +
286+
`Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` +
287+
`supports \`watch(source, cb, options?) signature.`
288+
);
289+
}
250290
options = cb as Partial<WatcherOption>;
251291
callback = null;
252292
}
253293

254-
const opts: WatcherOption = {
255-
...{
256-
lazy: false,
257-
deep: false,
258-
flush: 'post',
259-
},
260-
...options,
261-
};
262-
let vm = getCurrentVM();
263-
if (!vm) {
264-
if (!fallbackVM) {
265-
fallbackVM = defineComponentInstance(getCurrentVue());
266-
}
267-
vm = fallbackVM;
268-
} else if (!hasWatchEnv(vm)) {
269-
installWatchEnv(vm);
270-
}
294+
const opts = getWatcherOption(options);
295+
const vm = getWatcherVM();
271296

272297
return createWatcher(vm, source, callback, opts);
273298
}

test/apis/watch.spec.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const Vue = require('vue/dist/vue.common.js');
2-
const { ref, reactive, watch } = require('../../src');
2+
const { ref, reactive, watch, watchEffect } = require('../../src');
33

44
describe('api/watch', () => {
55
const anyFn = expect.any(Function);
@@ -298,11 +298,11 @@ describe('api/watch', () => {
298298
const x = ref(0);
299299

300300
// prettier-ignore
301-
watch(() => { void x.value; result.push('sync getter'); }, { flush: 'sync' });
301+
watchEffect(() => { void x.value; result.push('sync effect'); }, { flush: 'sync' });
302302
// prettier-ignore
303-
watch(() => { void x.value; result.push('pre getter'); }, { flush: 'pre' });
303+
watchEffect(() => { void x.value; result.push('pre effect'); }, { flush: 'pre' });
304304
// prettier-ignore
305-
watch(() => { void x.value; result.push('post getter'); }, { flush: 'post' });
305+
watchEffect(() => { void x.value; result.push('post effect'); }, { flush: 'post' });
306306

307307
// prettier-ignore
308308
watch(x, () => { result.push('sync callback') }, { flush: 'sync' })
@@ -321,24 +321,24 @@ describe('api/watch', () => {
321321
},
322322
template: `<div>{{x}}</div>`,
323323
}).$mount();
324-
expect(result).toEqual(['sync getter', 'sync callback', 'pre callback', 'post callback']);
324+
expect(result).toEqual(['sync effect', 'sync callback', 'pre callback', 'post callback']);
325325
result.length = 0;
326326

327327
waitForUpdate(() => {
328-
expect(result).toEqual(['pre getter', 'post getter']);
328+
expect(result).toEqual(['pre effect', 'post effect']);
329329
result.length = 0;
330330

331331
vm.inc();
332332
})
333333
.then(() => {
334334
expect(result).toEqual([
335335
'before inc',
336-
'sync getter',
336+
'sync effect',
337337
'sync callback',
338338
'after inc',
339-
'pre getter',
339+
'pre effect',
340340
'pre callback',
341-
'post getter',
341+
'post effect',
342342
'post callback',
343343
]);
344344
})
@@ -352,7 +352,7 @@ describe('api/watch', () => {
352352
const vm = new Vue({
353353
setup() {
354354
const count = ref(0);
355-
watch(_onCleanup => {
355+
watchEffect(_onCleanup => {
356356
onCleanup = _onCleanup;
357357
spy(count.value);
358358
renderedText = vm.$el.textContent;
@@ -384,7 +384,7 @@ describe('api/watch', () => {
384384
const vm = new Vue({
385385
setup() {
386386
const count = ref(0);
387-
watch(
387+
watchEffect(
388388
() => {
389389
spy(count.value);
390390
},
@@ -563,7 +563,7 @@ describe('api/watch', () => {
563563

564564
it('simple effect', done => {
565565
const obj = reactive({ a: 1 });
566-
watch(() => spy(obj.a));
566+
watchEffect(() => spy(obj.a));
567567
expect(spy).not.toHaveBeenCalled();
568568
waitForUpdate(() => {
569569
expect(spy).toBeCalledTimes(1);
@@ -596,10 +596,10 @@ describe('api/watch', () => {
596596
return p;
597597
}
598598

599-
it('work with (single getter)', done => {
599+
it('work with effect', done => {
600600
const id = ref(1);
601601
const promises = [];
602-
watch(onCleanup => {
602+
watchEffect(onCleanup => {
603603
const val = getAsyncValue(id.value);
604604
promises.push(val);
605605
onCleanup(() => {
@@ -617,10 +617,10 @@ describe('api/watch', () => {
617617
.then(done);
618618
});
619619

620-
it('run cleanup when watch stops (single getter)', done => {
620+
it('run cleanup when watch stops (effect)', done => {
621621
const spy = jest.fn();
622622
const cleanup = jest.fn();
623-
const stop = watch(onCleanup => {
623+
const stop = watchEffect(onCleanup => {
624624
spy();
625625
onCleanup(cleanup);
626626
});
@@ -651,7 +651,7 @@ describe('api/watch', () => {
651651
it('should not collect reactive in onCleanup', done => {
652652
const ref1 = ref(1);
653653
const ref2 = ref(1);
654-
watch(onCleanup => {
654+
watchEffect(onCleanup => {
655655
spy(ref1.value);
656656
onCleanup(() => {
657657
ref2.value = ref2.value + 1;

test/templateRefs.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
const Vue = require('vue/dist/vue.common.js');
2-
const { ref, watch, createElement: h } = require('../src');
2+
const { ref, watchEffect, createElement: h } = require('../src');
33

44
describe('ref', () => {
55
it('should work', done => {
66
let dummy;
77
const vm = new Vue({
88
setup() {
99
const ref1 = ref(null);
10-
watch(() => {
10+
watchEffect(() => {
1111
dummy = ref1.value;
1212
});
1313

@@ -35,7 +35,7 @@ describe('ref', () => {
3535
setup() {
3636
const ref1 = ref(null);
3737
const ref2 = ref(null);
38-
watch(() => {
38+
watchEffect(() => {
3939
dummy1 = ref1.value;
4040
dummy2 = ref2.value;
4141
});

0 commit comments

Comments
 (0)