Open unbrain opened 2 years ago
实现 readonly isReactive isReadonly stop onstop
1.他其实就是简单的 reactive 只是不可写 不收集依赖也不触发依赖
2.由于他们有不少的共同点 我们将代码的逻辑尽可能的抽离出来想源码靠拢
funtion createReactiveObject (target, baseHanlders) { return new Proxy(target, baseHandlers); } export function reactive(target) { return createReactiveObject(target, mutableHandlers); } export function readonly(target) { return createReactiveObject(target, readonlyHandlers); }
const get = createGetter(); const readOnly = createGetter(true); const set createSetter(); function createGetter(isReadOnly) { return function(target, key) { const res = Reflect.get(target, key); if(!isReadOnly) { track(target, key); } return res; } } function createSetter(isReadOnly) { return function(target, key, value) { const res = Reflect.set(target, key, value); trigger(target, key); return res; } } export function mutableHandlers() { return { get, set } } export function readonlyHandlers { return { get: readonlyGet, set(target, key){ console.warn(`set failed ${String(key)} is readonly`); return true; } } }
// reactive.ts export const enum ReactiveFlag { IS_REACTIVE = '__v_isReactive', IS_READONLY = '__v_isReadonly', } export function isReactive(target) { return !!(target[ReactiveFlag.IS_REACTIVE]) } export function isReadonly() { return !!(target[ReactiveFlag.IS_READONLY]) }
// baseHandler.ts function createGetter(isReadOnly) { return function(target, key) { if(key === target[ReactiveFlag.IS_REACTIVE]) { return !isReadOnly; } else if (target[ReactiveFlag.IS_READONLY]) { return isReadOnly; } } }
stop 要较为复杂些我们先写测试代码
describe('reactive', () => { it('stop', () => { const dummey; const obj = reactive({a: 1}); const runner = effect(() => { dummy = obj.a; }) expect(dummy).toBe(1); obj.a++; expect(dummy).toBe(2); stop(runner); obj++;//既有 get 也有 set expect(dummy).toBe(2); runner(); expect(dummy).toBe(3); }) })
1.get 会重新收集依赖,set 会触发依赖 所以 stop 后我们需要对这两部分都进行处理
let shouldTrack = false;// 是否执行依赖 let activeEffect; track() { // 最开始是若不执行我们将不收集依赖 这样重新 get 就不会触发手机 if(!shouldTrack) return; ... // 收集 dep 方便后续撤销副作用 activeEffect.deps.push(dep) } class ReactiveEffect { ... onStop?:()=> {}; active = true; deps = []; run() { // 不激活的直接执行 is(!this.active) { return this._fn() } shouldTrack = true; activeEffect = this; const res = this._fn(); shouldTrack = false; return res; } stop() { if(this.active) { cleanupEffect(this); this.onStop && this.onStop(); this.active = false; } } } const cleanupEffect = (effect) => { effect.deps.forEach(dep => { dep.delete(effect); }) } export function effect(fn, options = {}) { const _effect = new ReactiveEffect(fn, options.scheduler); extend(_effect, options); _effect.run(); const runner = _effect.run.bind(_effect); // 收集下 effect 方便调用 runner.effect = _effect; return runner; } exprt function stop (runner) { return runner.effect.stop(); }
Reactive Effect
实现 readonly isReactive isReadonly stop onstop
readonly
1.他其实就是简单的 reactive 只是不可写 不收集依赖也不触发依赖
2.由于他们有不少的共同点 我们将代码的逻辑尽可能的抽离出来想源码靠拢
isReactive isReadonly
stop
stop 要较为复杂些我们先写测试代码
1.get 会重新收集依赖,set 会触发依赖 所以 stop 后我们需要对这两部分都进行处理