Skip to content

Commit

Permalink
feat: stop and cleanup in watchEffect api
Browse files Browse the repository at this point in the history
  • Loading branch information
cuixiaorui committed Oct 7, 2022
1 parent ae48a05 commit 860fa9e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
35 changes: 35 additions & 0 deletions packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { reactive } from "@mini-vue/reactivity";
import { watchEffect } from "../src/apiWatch";
import { nextTick } from "../src/scheduler";
import { vi } from "vitest";

describe("api: watch", () => {
it("effect", async () => {
Expand All @@ -15,4 +16,38 @@ describe("api: watch", () => {
await nextTick();
expect(dummy).toBe(1);
});

it("stopping the watcher (effect)", async () => {
const state = reactive({ count: 0 });
let dummy;
const stop: any = watchEffect(() => {
dummy = state.count;
});
expect(dummy).toBe(0);

stop();
state.count++;
await nextTick();
// should not update
expect(dummy).toBe(0);
});

it("cleanup registration (effect)", async () => {
const state = reactive({ count: 0 });
const cleanup = vi.fn();
let dummy;
const stop: any = watchEffect((onCleanup) => {
onCleanup(cleanup);
dummy = state.count;
});
expect(dummy).toBe(0);

state.count++;
await nextTick();
expect(cleanup).toHaveBeenCalledTimes(1);
expect(dummy).toBe(1);

stop();
expect(cleanup).toHaveBeenCalledTimes(2);
});
});
26 changes: 24 additions & 2 deletions packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { queuePreFlushCb } from "./scheduler";

// Simple effect.
export function watchEffect(effect) {
doWatch(effect);
return doWatch(effect);
}

function doWatch(source) {
Expand All @@ -19,13 +19,35 @@ function doWatch(source) {
// 让回调可以在 render 前执行 变成一个异步的行为(这里也可以通过 flush 来改变)
const scheduler = () => queuePreFlushCb(job);

// cleanup 的作用是为了解决初始化的时候不调用 fn(用户传过来的 cleanup)
// 第一次执行 watchEffect 的时候 onCleanup 会被调用 而这时候只需要把 fn 赋值给 cleanup 就可以
// 当第二次执行 watchEffect 的时候就需要执行 fn 了 也就是 cleanup
let cleanup;
const onCleanup = (fn) => {
// 当 effect stop 的时候也需要执行 cleanup
// 所以可以在 onStop 中直接执行 fn
cleanup = effect.onStop = () => {
fn();
};
};
// 这里是在执行 effect.run 的时候就会调用的
const getter = () => {
source();
// 这个的检测就是初始化不执行 cleanup 的关键点
if (cleanup) {
cleanup();
}

source(onCleanup);
};

const effect = new ReactiveEffect(getter, scheduler);

// 这里执行的就是 getter
effect.run();

// 返回值为 StopHandle
// 只需要调用 stop 即可
return () => {
effect.stop();
};
}

0 comments on commit 860fa9e

Please sign in to comment.