谈谈 Vue toRef 和 reactive

Posted Himmelbleu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了谈谈 Vue toRef 和 reactive相关的知识,希望对你有一定的参考价值。

reactive

reactive 创建一个深层的对象的响应式代理,即对象根属性以及嵌套对象的属性都是响应式的。如果使用 ES6 结构赋值,就会使得这个对象的响应式代理第一层(根属性)属性失去响应式,但其嵌套下的对象属性还是响应式的。

shallowReactive 会创建浅层的对象的响应式代理,只有第一层(根属性)属性有响应式,其嵌套对象的属性不是响应式。

// 解构赋值
const  foo, bar  =  ...reactive( foo: 1, bar:  val: 1  ) ;
<div>foo:  foo </div>
<button @click="foo++">Change foo</button>
<div>bar val:  bar.val </div>
<button @click="bar.val++">Click bar val</button>

如上图所示,foo 只有在 bar.val 响应式更新之后才更新。被解构赋值之后,foo 是根属性,失去了响应式;bar 是嵌套对象,其属性还有响应式。

toRef

toRef基于响应式对象上的一个属性,创建一个对应的 ref。这里有非常重要的注意点,“响应式”、“对象”。toRef 操作的是一个响应式数据,且数据类型是对象,而不是一个普通对象,即便控制台不报错,也会失去它的意义。

const obj = 
  foo: 
    bar: 1
  
;

const state = toRef(obj, "foo");

function change() 
  state.value.bar++;
  console.log(state.value.bar, obj.foo.bar);

<div>obj:  obj.foo.bar </div>
<div>foo:  state.bar </div>
<button @click="change">Change foo bar</button>

如下图所示,页面不发生更新:

state 确实是 Ref 类型:

也就是说,toRef 操作的数据不能是普通对象的属性。

toRef 作用是什么?

延续响应式能力

下面是官方文档给出的示例,左看右看、上看下看都没看出个啥特别的。谜语人吧这是?

const state = reactive(
  foo: 1,
  bar: 2
)

const fooRef = toRef(state, \'foo\')

// 更改该 ref 会更新源属性
fooRef.value++
console.log(state.foo) // 2

// 更改源属性也会更新该 ref
state.foo++
console.log(fooRef.value) // 3

❓那么 toRef 有什么用呢?前面说到 reactive 被解构赋值之后第一层(根属性)失去了响应式,而 toRef 可以让其继续保持响应式。

toRef 当作 ref 函数创建一个响应式数据不是响应式的,页面不更新,前面图2 中已经说明了。toRef延续响应式能力,不是创建响应式数据

对第一节中的例子进行修改:

// 在 reactive 中包裹了 toRefs
const  foo, bar  =  ...toRefs(reactive( foo: 1, bar:  val: 1  )) ;

图4 与 图1 进行对比,foo 确确实实是响应式的,页面也发生了变化。不再因为 bar.val 更新而更新。

toRef 与 toRefs 的区别就是多了一个 s,即批量延续 reactive 的响应式能力。

转换 prop 为 Ref 类型

官方文档中有提到关于 prop 与 toRef 结合使用的案例,说非常有用。有些函数需要的参数类型就是 Ref,比如 useRefHistory,就需要传递 Ref 类型的数据:

组件 prop 不是一个 Ref 类型的数据:

console.log(isRef(props.foo)); // => false

因此,用 toRef 转换类型,与原始数据保持同步:

useRefHistory(toRef(props, "foo"));

总结

toRef 是延续响应式,不是创建响应式数据,不能等同于 ref 函数。为何是延续响应式,需要查阅源码方可知晓。本博客只是从表现中得到的结论,没有从原理上进行总结,属于经验之谈。

toRef 只能基于响应式数据进行操作,对普通的对象进行操作得到的数据不是响应式的。

以上是关于谈谈 Vue toRef 和 reactive的主要内容,如果未能解决你的问题,请参考以下文章

Vue 3 之:弄清 ref reactive toRef toRefs

vue3.2 响应式之 ref reactive toRef toRefs

vue3.2 响应式之 ref reactive toRef toRefs

Vue3的ref、reactive、toRef、toRefs

vue3+ts 中 ref与reactive 如何指定类型

Vue3官网-高级指南(十六)vue响应式原理步骤本质(副作用effect响应式状态reactive响应式原始值ref(解包)构造响应值toRefs)proxy(代理this)