实现 effect & reactive & 依赖收集 & 触发依赖
单测
因为 effect 整个测试流程很大,所以拆分出两块,分别是 effect 和 reactive 测试
1 2 3 4 5 6 7 8 9 10
| import { reactive } from '../reactive' describe('reactive', () => { it('happy path', () => { const original = { foo: 1 } const observer = reactive(original) expect(observer).not.toBe(original) expect(observed.foo).toBe(1) }) })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { effect } from '../effect' import { reactive } from '../reactive' describe('effect', () => { it('happy path', () => { const user = reactive({ age: 10 }) let nextAge effect(() => { nextAge = user.age + 1 }) expect(nextAge).toBe(11) user.age++ expect(nextAge).toBe(12) }) })
|
实现单测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import {track} from './effect'; export const reactive(raw)=>{ return new Proxy(raw,{ get:(target,key)=>{ const res = Reflect.get(target,key); track(target,key); return res; }, set:(target,key,value)=>{ const res = Reflect.set(target,key,value); trigger(target,key) return res; }, }) }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| let activeEffect class ReactiveEffect { private _fn: any constructor(fn) { this._fn = fn } run() { activeEffect = this this._fn() } }
const targetMap = new Map() export const track = (target, key) => { let depsMap = targetMap.get(target) if (!depsMap) { depsMap = new Map() targetMap.set(target, depsMap) } let dep = depsMap.get(key) if (!dep) { dep = new Set() depsMap.set(key, dep) } dep.add(activeEffect) }
const trigger = (target, key) => { let depsMap = targetMap.get(target) let dep = depsMap.get(key) for (const effect of dep) { effect.run() } } export const effect = fn => { const _effect = new ReactiveEffect(fn) _effect.run() }
|