Zum*_*umm 9 vue.js vue-component vue-reactivity vuejs3 vue-composition-api
我刚刚开始使用 Vue 3 和 Composition API。
我想知道ref
,toRef
和之间有什么区别toRefs
?
Xin*_*hao 22
反应性的
reactive
基于给定对象创建深度反应性代理 对象。代理对象看起来与给定的普通对象完全相同,但是任何突变,无论多深,都将是反应性的 - 这包括所有类型的突变,包括属性添加和删除。重要的是它只能处理对象,不能处理基元。reactive
例如,const state = reactive({foo: {bar: 1}})
意思是:
state.foo
是反应性的(它可以在模板、计算和监视中使用)state.foo.bar
是反应性的state.baz
, state.foo.baz
,state.foo.bar.baz
也是反应性的,即使baz
在任何地方都不存在。这可能看起来令人惊讶(尤其是当您开始挖掘 vue 中的反应性如何工作时)。通过state.baz
反应性,我的意思是在您的模板/计算属性/手表中,您可以按字面意思编写并期望您的逻辑在可用state.baz
时再次执行。事实上,即使你在模板中编写了类似的内容,它也可以工作。最终显示的字符串将反应性地反映 state.baz.qux。state.baz
{{ state.baz ? state.baz.qux : "default value" }}
之所以会发生这种情况,是因为reactive
它不仅创建单个顶级代理对象,而且还会递归地将所有嵌套对象转换为反应式代理,并且这个过程在运行时继续发生,即使对于动态创建的子对象也是如此。每当对反应性对象进行属性访问尝试时,就会在运行时不断发现和跟踪反应性对象属性的依赖关系。考虑到这一点,您可以{{ state.baz ? state.baz.qux : "default value" }}
逐步计算出这个表达式:
state
property进行属性访问baz
)。作为一个代理对象,state会记住你的表达式依赖于它的 property baz
,即使baz
它还不存在。反应性关闭由拥有该属性的对象baz
提供state
。state.baz
返回undefined
,表达式的计算结果为“默认值”,而无需查看state.baz.qux
。本轮中没有记录依赖关系state.baz.qux
,但这很好。因为如果不先变异就无法变异qux
baz
。state.baz
: state.baz = { qux: "hello" }
。此突变符合 属性的突变baz
,state
因此您的表达式计划重新评估。同时,分配给的state.baz
是动态创建的子代理{ qux: "hello" }
state.baz
不是undefined
,因此表达式进展为state.baz.qux
。返回“hello”,并qux
记录代理对象对属性的依赖关系state.baz
。这就是我所说的依赖关系在运行时发生时被发现并记录的意思。state.baz.qux = "hi"
。这是属性的突变qux
,因此您的表达式将再次被评估。考虑到上述内容,您应该也能够理解这一点:您可以存储state.foo
在单独的变量中:const foo = state.foo
。foo
反应性可以很好地处理你的变量。foo
指向相同的东西state.foo
- 反应式代理对象。反应性的力量来自代理对象。顺便说一下,const baz = state.baz
效果不一样,稍后会详细介绍。
然而,总是有一些边缘情况需要注意:
baz
所创建的变量const baz = state.baz
,也不能bar
消除 的变量const bar = state.foo.bar
。明确地说,这意味着您可以在模板/计算/监视中使用state.baz
and ,但不能在上面使用or创建。state.foo.bar
baz
bar
state.foo = {bar: 3}
) 不会破坏 的反应性foo
,但state.foo
将是一个新的代理对象,而foo
变量仍然指向原始代理对象。const state = reactive({foo: {bar: 1}});
const foo = state.foo;
state.foo.bar = 2;
foo.bar === 2; // true, because foo and state.foo are the same
state.foo = {bar: 3};
foo.bar === 3; // false, foo.bar will still be 2
Run Code Online (Sandbox Code Playgroud)
ref
并toRef
解决其中一些边缘情况。
参考
ref
几乎reactive
也适用于基元。我们仍然无法将 JS 原语转换为 Proxy 对象,因此ref
始终将提供的参数包装X
为 shape 的对象{value: X}
。无论 X 是否原始,“拳击”总是会发生。如果将一个对象赋予ref
,则在装箱后ref
内部调用,因此结果也是深度反应的。实践中的主要区别是,在使用 ref 时,reactive
您需要记住调用js 代码。.value
在模板中,您不必调用,.value
因为 Vue 会自动解开模板中的 ref。
const count = ref(1);
const objCount = ref({count: 1});
count.value === 1; // true
objCount.value.count === 1; // true
Run Code Online (Sandbox Code Playgroud)
参考文献
toRef
旨在将反应对象的属性转换为ref
. 您可能想知道为什么这是必要的,因为反应性对象已经是深度反应性的。toRef
在这里处理提到的两种边缘情况reactive
。总之,toRef
可以将响应式对象的任何属性转换为链接到其原始父级的引用。该属性可以是最初不存在的属性,也可以是原始值。
在同一示例中,状态定义为const state = reactive({foo: {bar: 1}})
:
const foo = toRef(state, 'foo')
与以下内容非常相似,const foo = state.foo
但有两点不同:
foo
是一个ref
所以你需要在js中做foo.value
;foo
链接到其父级,因此重新分配state.foo = {bar: 2}
将反映在foo.value
const baz = toRef(state, 'baz')
现在可以了。参考文献
toRefs
是一个实用方法,用于破坏反应对象并将其所有属性转换为 ref:
const state = reactive({...});
return {...state}; // will not work, destruction removes reactivity
return toRefs(state); // works
Run Code Online (Sandbox Code Playgroud)
Dan*_*Dan 13
ref
甲REF是用于Vue公司3的想法是包裹非对象在一个反应性的机构reactive
对象:
接受一个内部值并返回一个反应性和可变的 ref 对象。ref 对象有一个
.value
指向内部值的属性。
嗯.. 为什么?
了解在 JavaScript(和许多 OOP 语言)中,有两种类型的变量:值和引用。
如果一个变量x
包含一个 value 5
,那么如果你复制x
到y
,你就复制了一个值。将来对 的任何更改x
都不会更改y
。但是,如果x
包含一个对象(引用类型),那么y
不变更如果x
的性质发生变化,因为它们都指代相同的对象。
这使得引用类型更加动态;您可以复制它们并通过更改原件来更改副本,甚至可以通过更改副本来更改原件。Vue 想要利用这种能力,即使对于数字这样的值类型,它也允许你将它们“包装”在一个对象中以创建一个引用变量。
reactive
对于对象变量,不需要 ref 包装,因为它已经是引用类型。它只需要 Vue 的响应式功能(ref 也有):
const state = reactive({
foo: 1,
bar: 2
})
Run Code Online (Sandbox Code Playgroud)
但是如果这个对象的属性是值变量,它们自然就不是 refs。这意味着如果您要直接复制一个属性,您将失去与其父对象的连接。这toRef
是有用的地方。
toRef
toRef
将单个reactive
对象属性转换为保持与父对象连接的 ref:
Run Code Online (Sandbox Code Playgroud)const state = reactive({ foo: 1, bar: 2 }) const fooRef = toRef(state, 'foo') /* fooRef: Ref<number>, */
toRefs
toRefs
将所有属性转换为具有 refs 属性的普通对象:
Run Code Online (Sandbox Code Playgroud)const state = reactive({ foo: 1, bar: 2 }) const stateAsRefs = toRefs(state) /* { foo: Ref<number>, bar: Ref<number> } */