解答-2
如何理解 ref toRef toRefs
细节的知识点,在整个 Composition API 中算是比较难理解的。 甚至出现了 ref sugar 的讨论。
ref 和 reactive 结合起来使用,更是难以理解。 既然有 reactive ,为何还要 ref 呢???
https://v3.cn.vuejs.org/api/refs-api.html
ref
创建响应式对象一般用 reactive
第一,响应式 (代码参考 RefBasic.vue)
- 生成值类型的响应式数据
- 可直接用于模板和 reactive
- 可通过
.value修改值
第二,模板引用(代码参考 RefTemplate.vue)
toRef
代码参考 ToRef.vue
可以用来为源响应式对象上的 property 新创建一个 ref。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。
- 针对一个响应式对象的 property
- 创建一个 ref 具有响应式
- 保持引用关系
【注意】必须是响应式对象,普通对象不具有响应式。
toRefs
代码参考 ToRefs.vue
将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref 。
- 将响应式对象转换为普通对象 obj
- obj 的每个属性都是对应的 ref
- 保持引用关系
【注意】必须是响应式对象,普通对象不具有响应式。
当从合成函数返回响应式对象时,toRefs 非常有用。 这样消费组件就可以在不丢失响应性的情况下对返回的对象进行分解/扩散:
function useFeatureX() {
const state = reactive({
x: 1,
y: 2
})
// 逻辑运行状态,省略 N 行
// 返回时转换为ref
return toRefs(state)
}
export default {
setup() {
// 可以在不失去响应性的情况下破坏结构
const { x, y } = useFeatureX()
return {
x,
y
}
}
}ref 和 reactive
既然有 reactive ,为何还要 ref 呢?
- 返回值类型,会丢失响应式
- 如在 setup、computed、合成函数,都有可能返回值类型
- Vue 如不定义 ref ,用户将自造 ref ,反而混乱
代码参考 ref/WhyRef.vue
为何需要 .value
- 因为要保证响应式,需要把值类型封装成一个对象形式,所以用
.value表示这个值 - 模板,reactive 使用时,不需要
.value - 其他情况都需要
.value
结合 computed 的内部实现,可如下解释:
// 伪代码:不具有响应式,即改变值不会触发渲染
function computed(getter) {
let value
watchEffect(() => {
value = getter() // value 是值类型,值拷贝,value 的变化不会传递到下游
})
return value
}
// 伪代码:具有响应式
function computed(getter) {
const ref = {
value: null,
}
watchEffect(() => {
ref.value = getter() // ref 是引用类型,指针拷贝,ref 的变化会传递到下游
})
return ref
}上述代码,可以把 watchEffect 改为 setTimeout 模拟一下
再聊 toRef 和 toRefs
- 设计初衷:不丢失响应性的情况下对返回的对象进行分解/扩散
- 必须存在:因为直接 property 或者
...state,会直接拿到属性的值。如果属性是值类型,则会丢失响应式 !!!(响应式是 Proxy 实现的) - 注意事项:不创造响应式,而是延续响应式 (所以针对普通对象不行,必须是响应式对象)
toRef toRefs 必须针对一个响应式对象,普通对象是无法变成响应式的。 它俩的设计初衷,本来也是针对响应式对象的 https://vue-composition-api-rfc.netlify.app/zh/api.html#toref 即,想要实现响应式,只有两个方法:ref reactive
ref创造响应式toRef和toRefs延续响应式
为何必须使用 toRef(state, 'name') 和 toRefs(state) ??? 因为直接 property 或者 ...state ,会直接拿到属性的值。如果属性是值类型,则会丢失响应式。(响应式是 Proxy 实现的) 这也是引入 ref 的根源!!! 也是引入 Composition API ,抛弃 this ,带来的结果。
从使用角度
理解和应用要分开总结,这很重要。即便你听不懂原理,也要知道如何使用。
- ref 值类型响应式
- ref 模板引用
- setup 返回时用
toRefs(state) - 用于第三方的逻辑函数,如 demo 中的
useMousePosition - 为所有的 ref 名加类似
xxxRef的后缀
ref 和 reactive 混合起来,真的非常乱。 相比之下,React Hooks 只有 useState ,反而简单很多。—— 当然它也有其他的一些理解成本。

讨论区
欢迎留下想法与补充