Skip to content

Commit 982f798

Browse files
committed
修复effect内嵌套effect的问题
1 parent e73d64a commit 982f798

File tree

4 files changed

+108
-9
lines changed

4 files changed

+108
-9
lines changed

src/reactive/effect.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
11
import { extend } from "../shared/index";
22

3-
let activeEffect: ReactiveEffect;
3+
// 这里使用一个变量保存活跃的effect,
4+
// 但是如果存在effect嵌套的情况,就会有问题,需要把这个变成一个栈。
5+
let activeEffect: ReactiveEffect | undefined;
6+
const effectStack: ReactiveEffect[] = [];
47
let shouldTrack;
58
const targetMap = new WeakMap();
69

10+
const trackStack: boolean[] = [];
11+
12+
export function pauseTracking() {
13+
trackStack.push(shouldTrack);
14+
shouldTrack = false;
15+
}
16+
17+
export function enableTracking() {
18+
trackStack.push(shouldTrack);
19+
shouldTrack = true;
20+
}
21+
22+
export function resetTracking() {
23+
const last = trackStack.pop();
24+
shouldTrack = last === undefined ? true : last;
25+
}
26+
727
export class ReactiveEffect {
828
// effect传递的第一个参数
929
private _fn: (...args) => void;
@@ -21,16 +41,22 @@ export class ReactiveEffect {
2141
}
2242

2343
run(...args) {
24-
activeEffect = this;
2544
if (!this.active) {
2645
return this._fn(...args);
2746
}
28-
29-
shouldTrack = true;
30-
31-
const res = this._fn(...args);
32-
shouldTrack = false;
33-
return res;
47+
if (!effectStack.includes(this)) {
48+
effectStack.push((activeEffect = this));
49+
50+
//
51+
enableTracking()
52+
53+
const res = this._fn(...args);
54+
resetTracking()
55+
effectStack.pop();
56+
const n = effectStack.length;
57+
activeEffect = n > 0 ? effectStack[n - 1] : undefined;
58+
return res;
59+
}
3460
}
3561

3662
stop() {
@@ -68,7 +94,8 @@ export function track(target, key) {
6894

6995
export function trackEffects(dep) {
7096
dep.add(activeEffect);
71-
activeEffect.deps.push(dep);
97+
98+
activeEffect!.deps.push(dep);
7299
}
73100

74101
export function isTracking() {
@@ -79,6 +106,7 @@ export function trigger(target, key) {
79106
const depsMap = targetMap.get(target);
80107
if (!depsMap) return;
81108
const dep = depsMap.get(key);
109+
82110
triggerEffects(dep);
83111
}
84112

src/reactive/effectScope.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export class EffectScope {
2+
effects: any[] = []
3+
run(fn) {
4+
const res = fn()
5+
return res
6+
}
7+
}
8+
9+
export function effectScope() {}

src/reactive/test/effect.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,31 @@ describe("effect", () => {
101101
stop(runner);
102102
expect(onStop).toBeCalledTimes(1);
103103
});
104+
105+
106+
it("nested effect", () => {
107+
let dummy;
108+
let dummy1;
109+
let obj = reactive({
110+
count: 1,
111+
});
112+
113+
// effect1 effect2
114+
// 执行effect1过程又会
115+
effect(() => {
116+
console.log(111);
117+
effect(() => {
118+
console.log(222);
119+
120+
dummy = obj.count;
121+
});
122+
dummy1 = obj.count;
123+
});
124+
125+
expect(dummy).toBe(1);
126+
expect(dummy1).toBe(1);
127+
obj.count = 2;
128+
expect(dummy).toBe(2);
129+
expect(dummy1).toBe(2);
130+
});
104131
});

src/reactive/test/effectScope.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { reactive } from "../reactive";
2+
import { effect } from "../effect";
3+
import { effectScope, EffectScope } from "../effectScope";
4+
5+
describe("reactivity/effect/scope", () => {
6+
it("should run", () => {
7+
const fnSpy = jest.fn(() => {});
8+
new EffectScope().run(fnSpy);
9+
expect(fnSpy).toHaveBeenCalledTimes(1);
10+
});
11+
12+
it("should accept zero argument", () => {
13+
const scope = new EffectScope();
14+
expect(scope.effects.length).toBe(0);
15+
});
16+
17+
it("should return run value", () => {
18+
expect(new EffectScope().run(() => 1)).toBe(1);
19+
});
20+
21+
// it("should collect the effects", () => {
22+
// const scope = new EffectScope();
23+
// scope.run(() => {
24+
// let dummy;
25+
// const counter = reactive({ num: 0 });
26+
// effect(() => (dummy = counter.num));
27+
28+
// expect(dummy).toBe(0);
29+
// counter.num = 7;
30+
// expect(dummy).toBe(7);
31+
// });
32+
33+
// expect(scope.effects.length).toBe(1);
34+
// });
35+
});

0 commit comments

Comments
 (0)