ref 为什么需要 .value

7,060 阅读1分钟

大家好,我是哈默。今天我们来说一下为什么 ref 中我们需要 .value

ref 不是由 Proxy 实现的

经过之前的文章,我们已经知道了 ref 并不是由 Proxy 来实现的:ref是一个RefImpl对象

所以它可以接收 原始类型的数据,但是 数据的响应性 是如何处理的呢?

RefImpl 类的实现

首先,我们知道,Proxy 实现响应式的关键,在于它能监听 被代理对象 的 getter 行为 和 setter 行为:

const proxyObj = new Proxy(obj, {
  set() {
    // 监听了 setter 行为
    console.log("触发了 set,设置了值");
  },
  get() {
    // 监听了 getter 行为
    console.log("触发了 get,读取了值");
  },
});

那么对于 ref 而言,我们可以来到 Vue 的源码中,查看一下 RefImpl 类的实现:

class RefImpl<T> {
  ...

  constructor(value: T, public readonly __v_isShallow: boolean) {
    ...
  }

  get value() {
    trackRefValue(this)
    return this._value
  }

  set value(newVal) {
    ...
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal
      this._value = useDirectValue ? newVal : toReactive(newVal)
      triggerRefValue(this, newVal)
    }
  }
}

有意思的是,我们看到了叫做 get value() 和 set value() 的东西。

那么在我们使用的时候,什么时候会触发 get value() 呢?就是当我们 xxxRef.value 的时候 ; 什么时候会触发 set value() 呢?就是当我们xxxRef.value = '100' 的时候。

也就是说,我们通过 .value 就可以成功触发 get value() 和 set value() ,从而成功的监听到我们 读取值 和 设置值 的行为。

也就是实现了和 Proxy 一样的效果,这样一来 数据的响应性 也可以在这两种行为中被处理。

总结

.value 的存在就是让我们能通过 ref 也能实现数据的响应性。