Reactivity

reactive 是vue响应式的核心

reactive 一般和 effect 结合使用

const { reactive, effect } = VueReactivity

const state = reactive({ name: 'kortin', age: 23 })

effect(() => {
	el.innerHTML = state.name + '今年' + state.age + '岁了'
})

setTimeout(() => {
	state.age ++
}, 3000)

上面例子中,

实现reactive

1) 简单的 Proxy 代理对象

export function reactive<T extends object>(target: T) {
  if (!isObject(target)) return;
  return new Proxy(target, {
    // 取值时会调用get
    get(target, key, receiver) {
      return target[key]
    },
    // 赋值时会调用set
    set(target, key, value, receiver) {
      target[key] = value
      return true
    }
  })
}

2) Reflect 解决 this 指向问题

let person = {
  firstName: '周',
  lastName: '昊天',
  get name() {
    return this.firstName + this.lastName
  }
}

如果访问了 name (对象属性访问器),而 name 依赖访问了 firstNamelastName

这种情况下, firstNamelastName 的依赖都应该被收集。

为了解决上面的问题,需要引入 Reflect

export function reactive<T extends object>(target: T) {
  if (!isObject(target)) return;
  return new Proxy(target, {
    get(target, key, receiver) {
     return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      return Reflect.set(target, key, value, receiver)
    }
  }

receiver 就是当前的 Proxy 对象,通过 Reflect 在读取 target 属性时将 this 指向到当前的 Proxy 对象上。

3) 同一个 target 重复声明响应式

如果同一个 target 对象进行了两次响应式声明后 new 了两个 Proxy 对象,显然两个 Proxy 对象是不相等的,实际上,同一个对象的响应式对象应该也是相同的。