Vue 3 中的 ref vs 反应式?
ref vs reactive in Vue 3?
查看一些人的 Vue 3 预览教程示例。[目前正在测试]
我找到了两个例子:
被动
<template>
<button @click="increment">
Count is: {{ state.count }}, double is: {{ state.double }}
</button>
</template>
<script>
import { reactive, computed } from 'vue'
export default {
setup() {
const state = reactive({
count: 0,
double: computed(() => state.count * 2)
})
function increment() {
state.count++
}
return {
state,
increment
}
}
}
</script>
参考
<template>
<div>
<h2 ref="titleRef">{{ formattedMoney }}</h2>
<input v-model="delta" type="number">
<button @click="add">Add</button>
</div>
</template>
<script>
import { ref, computed, onMounted } from "vue";
export default {
setup(props) {
// State
const money = ref(1);
const delta = ref(1);
// Refs
const titleRef = ref(null);
// Computed props
const formattedMoney = computed(() => money.value.toFixed(2));
// Hooks
onMounted(() => {
console.log("titleRef", titleRef.value);
});
// Methods
const add = () => (money.value += Number(delta.value));
return {
delta,
money,
titleRef,
formattedMoney,
add
};
}
};
</script>
ref
和 reactive
之间有一些相似之处,因为它们都提供了一种存储数据的方法并允许该数据具有反应性。
但是:
高阶差异:
You can’t use reactive() on primitives (strings, numbers, booleans) - that’s what you need refs for, because you will have situations where you need to have a “reactive boolean”, for example…
of course your can create an object that wraps the primitive value and make that reactive():
const wrappedBoolean = reactive({
value: true
})
and just like that, you reinvented a ref.
被动
reactive
获取对象并 returns 对原始对象产生反应 proxy
。
例子
import {ref, reactive} from "vue";
export default {
name: "component",
setup() {
const title = ref("my cool title")
const page = reactive({
contents: "meh?",
number: 1,
ads: [{ source: "google" }],
filteredAds: computed(() => {
return ads.filter(ad => ad.source === "google")
})
})
return {
page,
title
}
}
}
说明
在上面,每当我们想要更改或访问 page
、
的属性时
说 page.ads
,page.filteredAds
将通过代理更新。
下面您可以看到我们的示例在上半部分使用 Reactive References,在其他替代反应语法下面。
//reactivity with ref syntax
import { ref, computed } from vue
export default {
setup() {
const capacity = ref(4)
const members = ref(["Tim", "John", "Andr"])
const simpleComputed = computed(() => {
return capacity.value - members.value.length
})
return { capacity, members, simpleComputed }
}
}
//reactivity with reactive syntax
import { reactive, computed } from vue
export default {
setup() {
const event = reactive({
capacity: 4,
members: ["Tim", "John", "Andr"]
simpleComputed: computed(() => {
return event.capacity - event.capacity.length
}
})
return { event }
}
}
正如上面代码底部所示,我创建了一个新的事件常量,它采用普通 JavaScript 对象和 returns 反应对象。在我们的常规组件语法中使用数据选项可能看起来很熟悉,我也发送了一个对象。但是,正如您在上面看到的,我还可以将我们的计算属性发送到该对象中。您还应该注意到,当我使用这种语法时,我们在访问属性时不再需要编写 .value。这是因为我只是访问事件对象的对象属性。您还应该注意到我们正在返回整个事件
两种语法都适用,但都不是最佳实践
要点
reactive()
只接受对象,NOT JS 原语(String, Boolean, Number, BigInt, Symbol, null, undefined)
ref()
正在幕后调用 reactive()
- 由于
reactive()
对对象起作用并且 ref()
调用 reactive()
,对象对两者都起作用
- 但是,
ref()
有一个 .value
属性 用于重新分配,reactive()
没有这个,因此不能重新分配
使用
ref()
当..
- 这是一个原始的(例如
'string'
、true
、23
等)
- 这是您需要稍后重新分配的对象(如数组 - more info here)
reactive()
当..
- 这是一个您不需要重新分配的对象,您希望避免
ref()
的开销
总结
ref()
似乎是可行的方法,因为它支持所有对象类型并允许使用 .value
重新分配。 ref()
是一个很好的起点,但是当您习惯了 API 时,要知道 reactive()
的开销较小,您可能会发现它更能满足您的需求。
ref()
用例
您将始终对基元使用 ref()
,但 ref()
适用于需要重新分配的对象,例如数组。
setup() {
const blogPosts = ref([]);
return { blogPosts };
}
getBlogPosts() {
this.blogPosts.value = await fetchBlogPosts();
}
上面的 reactive()
需要重新分配一个 属性 而不是整个对象。
setup() {
const blog = reactive({ posts: [] });
return { blog };
}
getBlogPosts() {
this.blog.posts = await fetchBlogPosts();
}
reactive()
用例
reactive()
的一个很好的用例是一组属于一起的原语:
const person = reactive({
name: 'Albert',
age: 30,
isNinja: true,
});
上面的代码感觉比
更合乎逻辑
const name = ref('Albert');
const age = ref(30);
const isNinja = ref(true);
有用的链接
如果您仍然迷路,这个简单的指南对我有帮助:https://www.danvega.dev/blog/2020/02/12/vue3-ref-vs-reactive/
仅使用 ref()
的论点:https://dev.to/ycmjason/thought-on-vue-3-composition-api-reactive-considered-harmful-j8c
为什么 reactive()
和 ref()
存在的背后的决策以及其他重要信息,Vue Composition API RFC:https://vuejs.org/guide/extras/composition-api-faq.html#why-composition-api
ref / reactive 都被用来创建跟踪变化的反应对象。
参考:
它接受一个原语参数和return一个反应性可变对象。该对象只有一个 属性 ‘value’,它将指向它所采用的参数。
被动:
它接受一个 JavaScript 对象作为参数和 return 对象的基于代理的反应副本。
参考与反应:
通常,ref 和 reactive 都用于创建反应对象,其中 ref 用于使原始值成为反应对象(布尔值、数字、字符串)。但是反应式不适用于基元而不是它适用于对象。
更多详情:参考Ref vs Reactive
参考:
它需要一个原语参数和 returns 一个反应性可变对象。该对象有一个 属性 ‘值’,它将指向它所采用的参数。
反应性:
它需要一个 JavaScript 对象作为参数,returns 对象的基于代理的反应副本。
您可以通过此视频教程了解更多信息:
https://www.youtube.com/watch?v=JJM7yCHLMu4
我将简单解释为什么有两种创建反应状态的方法:
其他答案已经看出两者的区别
reactive
: Create a reactive state. Returns a reactive proxy of the object:
import { reactive } from 'vue'
const reactiveObj = reactive({ count: 0 })
reactiveObj.count++
使用选项 API 我们过去常常在 data()
中保持反应状态。使用 Composition API 我们可以使用 reactive
API 实现相同的效果。到目前为止,还不错,但是...
Why do we need ref
???
只是因为 reactive
有限制,例如:
- 反应性损失:
const state = reactive({ count: 0 })
// the function receives a plain number and
// won't be able to track changes to state.count
callSomeFunction(state.count)
const state = reactive({ count: 0 })
let { count } = state
// does not affect original state
count++
let state = reactive({ count: 0 })
// this won't work!
state = reactive({ count: 1 })
- 它不能容纳原始类型,例如字符串、数字或布尔值。
So ref
, was provided by Vue to address the limitations of reactive
.
ref()
接受参数并且 returns 它包裹在一个 ref 对象中,其值为 属性:
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
参考可以:
- 持有任何值类型
- 反应性地替换整个对象:
const objectRef = ref({ count: 0 })
// this works reactively
objectRef.value = { count: 1 }
- 在不失去反应性的情况下传递给函数或从普通对象中解构
const obj = {
foo: ref(1),
bar: ref(2)
}
// the function receives a ref
// it needs to access the value via .value but it
// will retain the reactivity connection
callSomeFunction(obj.foo)
// still reactive
const { foo, bar } = obj
Should I always use ref
?
个人意见如下
大多数尝试过这两种方法的开发者建议使用我阅读过的文章中的 ref
。
但我个人认为 ref
与 reactive
具有相同的局限性,如果使用不当,您很容易陷入“反应性损失”的问题。
ref
也有一些行为,例如:
- 在模板中展开,但这只发生在 top-level 属性上
- 展开里面
reactive
- 当从数组或本地集合类型(如 Map)访问 ref 时不执行解包
- 参考同步
每次都必须处理 .value
有点令人困惑,Vue 知道这一点,并且在撰写本文时有一个 RFC - Reactivity Transform 旨在提供解决方案。
我希望您现在对 reactive
和 ref
有了更好的理解,但我认为值得一提的是,您应该了解更多关于反应状态的 API: readonly、shallowRef、shallowReactive、shallowReadonly、unref 等等。
ref
对象采用内部值,returns 是一个反应性和可变对象。通常用于String、Boolean、Number等原始类型单变量
reactive
是一个包装对象,它接受一个对象和 returns 原始对象的反应代理。通常用于 dictionary-structured 类型,例如 JS 对象。
您可以在本文中了解更多关于 ref 与 reactive 的信息:
https://dev.to/hirajatamil/must-know-ref-vs-reactive-differences-in-vue-3-composition-api-3bp4
查看一些人的 Vue 3 预览教程示例。[目前正在测试]
我找到了两个例子:
被动
<template>
<button @click="increment">
Count is: {{ state.count }}, double is: {{ state.double }}
</button>
</template>
<script>
import { reactive, computed } from 'vue'
export default {
setup() {
const state = reactive({
count: 0,
double: computed(() => state.count * 2)
})
function increment() {
state.count++
}
return {
state,
increment
}
}
}
</script>
参考
<template>
<div>
<h2 ref="titleRef">{{ formattedMoney }}</h2>
<input v-model="delta" type="number">
<button @click="add">Add</button>
</div>
</template>
<script>
import { ref, computed, onMounted } from "vue";
export default {
setup(props) {
// State
const money = ref(1);
const delta = ref(1);
// Refs
const titleRef = ref(null);
// Computed props
const formattedMoney = computed(() => money.value.toFixed(2));
// Hooks
onMounted(() => {
console.log("titleRef", titleRef.value);
});
// Methods
const add = () => (money.value += Number(delta.value));
return {
delta,
money,
titleRef,
formattedMoney,
add
};
}
};
</script>
ref
和 reactive
之间有一些相似之处,因为它们都提供了一种存储数据的方法并允许该数据具有反应性。
但是:
高阶差异:
You can’t use reactive() on primitives (strings, numbers, booleans) - that’s what you need refs for, because you will have situations where you need to have a “reactive boolean”, for example…
of course your can create an object that wraps the primitive value and make that reactive():
const wrappedBoolean = reactive({
value: true
})
and just like that, you reinvented a ref.
被动
reactive
获取对象并 returns 对原始对象产生反应 proxy
。
例子
import {ref, reactive} from "vue";
export default {
name: "component",
setup() {
const title = ref("my cool title")
const page = reactive({
contents: "meh?",
number: 1,
ads: [{ source: "google" }],
filteredAds: computed(() => {
return ads.filter(ad => ad.source === "google")
})
})
return {
page,
title
}
}
}
说明
在上面,每当我们想要更改或访问 page
、
的属性时
说 page.ads
,page.filteredAds
将通过代理更新。
下面您可以看到我们的示例在上半部分使用 Reactive References,在其他替代反应语法下面。
//reactivity with ref syntax
import { ref, computed } from vue
export default {
setup() {
const capacity = ref(4)
const members = ref(["Tim", "John", "Andr"])
const simpleComputed = computed(() => {
return capacity.value - members.value.length
})
return { capacity, members, simpleComputed }
}
}
//reactivity with reactive syntax
import { reactive, computed } from vue
export default {
setup() {
const event = reactive({
capacity: 4,
members: ["Tim", "John", "Andr"]
simpleComputed: computed(() => {
return event.capacity - event.capacity.length
}
})
return { event }
}
}
正如上面代码底部所示,我创建了一个新的事件常量,它采用普通 JavaScript 对象和 returns 反应对象。在我们的常规组件语法中使用数据选项可能看起来很熟悉,我也发送了一个对象。但是,正如您在上面看到的,我还可以将我们的计算属性发送到该对象中。您还应该注意到,当我使用这种语法时,我们在访问属性时不再需要编写 .value。这是因为我只是访问事件对象的对象属性。您还应该注意到我们正在返回整个事件
两种语法都适用,但都不是最佳实践
要点
reactive()
只接受对象,NOT JS 原语(String, Boolean, Number, BigInt, Symbol, null, undefined)ref()
正在幕后调用reactive()
- 由于
reactive()
对对象起作用并且ref()
调用reactive()
,对象对两者都起作用 - 但是,
ref()
有一个.value
属性 用于重新分配,reactive()
没有这个,因此不能重新分配
使用
ref()
当..
- 这是一个原始的(例如
'string'
、true
、23
等) - 这是您需要稍后重新分配的对象(如数组 - more info here)
reactive()
当..
- 这是一个您不需要重新分配的对象,您希望避免
ref()
的开销
总结
ref()
似乎是可行的方法,因为它支持所有对象类型并允许使用 .value
重新分配。 ref()
是一个很好的起点,但是当您习惯了 API 时,要知道 reactive()
的开销较小,您可能会发现它更能满足您的需求。
ref()
用例
您将始终对基元使用 ref()
,但 ref()
适用于需要重新分配的对象,例如数组。
setup() {
const blogPosts = ref([]);
return { blogPosts };
}
getBlogPosts() {
this.blogPosts.value = await fetchBlogPosts();
}
上面的 reactive()
需要重新分配一个 属性 而不是整个对象。
setup() {
const blog = reactive({ posts: [] });
return { blog };
}
getBlogPosts() {
this.blog.posts = await fetchBlogPosts();
}
reactive()
用例
reactive()
的一个很好的用例是一组属于一起的原语:
const person = reactive({
name: 'Albert',
age: 30,
isNinja: true,
});
上面的代码感觉比
更合乎逻辑const name = ref('Albert');
const age = ref(30);
const isNinja = ref(true);
有用的链接
如果您仍然迷路,这个简单的指南对我有帮助:https://www.danvega.dev/blog/2020/02/12/vue3-ref-vs-reactive/
仅使用 ref()
的论点:https://dev.to/ycmjason/thought-on-vue-3-composition-api-reactive-considered-harmful-j8c
为什么 reactive()
和 ref()
存在的背后的决策以及其他重要信息,Vue Composition API RFC:https://vuejs.org/guide/extras/composition-api-faq.html#why-composition-api
ref / reactive 都被用来创建跟踪变化的反应对象。
参考:
它接受一个原语参数和return一个反应性可变对象。该对象只有一个 属性 ‘value’,它将指向它所采用的参数。
被动:
它接受一个 JavaScript 对象作为参数和 return 对象的基于代理的反应副本。
参考与反应:
通常,ref 和 reactive 都用于创建反应对象,其中 ref 用于使原始值成为反应对象(布尔值、数字、字符串)。但是反应式不适用于基元而不是它适用于对象。
更多详情:参考Ref vs Reactive
参考: 它需要一个原语参数和 returns 一个反应性可变对象。该对象有一个 属性 ‘值’,它将指向它所采用的参数。
反应性: 它需要一个 JavaScript 对象作为参数,returns 对象的基于代理的反应副本。
您可以通过此视频教程了解更多信息: https://www.youtube.com/watch?v=JJM7yCHLMu4
我将简单解释为什么有两种创建反应状态的方法:
其他答案已经看出两者的区别
reactive
: Create a reactive state. Returns a reactive proxy of the object:
import { reactive } from 'vue'
const reactiveObj = reactive({ count: 0 })
reactiveObj.count++
使用选项 API 我们过去常常在 data()
中保持反应状态。使用 Composition API 我们可以使用 reactive
API 实现相同的效果。到目前为止,还不错,但是...
Why do we need
ref
???
只是因为 reactive
有限制,例如:
- 反应性损失:
const state = reactive({ count: 0 })
// the function receives a plain number and
// won't be able to track changes to state.count
callSomeFunction(state.count)
const state = reactive({ count: 0 })
let { count } = state
// does not affect original state
count++
let state = reactive({ count: 0 })
// this won't work!
state = reactive({ count: 1 })
- 它不能容纳原始类型,例如字符串、数字或布尔值。
So
ref
, was provided by Vue to address the limitations ofreactive
.
ref()
接受参数并且 returns 它包裹在一个 ref 对象中,其值为 属性:
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
参考可以:
- 持有任何值类型
- 反应性地替换整个对象:
const objectRef = ref({ count: 0 })
// this works reactively
objectRef.value = { count: 1 }
- 在不失去反应性的情况下传递给函数或从普通对象中解构
const obj = {
foo: ref(1),
bar: ref(2)
}
// the function receives a ref
// it needs to access the value via .value but it
// will retain the reactivity connection
callSomeFunction(obj.foo)
// still reactive
const { foo, bar } = obj
Should I always use
ref
?
个人意见如下
大多数尝试过这两种方法的开发者建议使用我阅读过的文章中的 ref
。
但我个人认为 ref
与 reactive
具有相同的局限性,如果使用不当,您很容易陷入“反应性损失”的问题。
ref
也有一些行为,例如:
- 在模板中展开,但这只发生在 top-level 属性上
- 展开里面
reactive
- 当从数组或本地集合类型(如 Map)访问 ref 时不执行解包
- 参考同步
每次都必须处理 .value
有点令人困惑,Vue 知道这一点,并且在撰写本文时有一个 RFC - Reactivity Transform 旨在提供解决方案。
我希望您现在对 reactive
和 ref
有了更好的理解,但我认为值得一提的是,您应该了解更多关于反应状态的 API: readonly、shallowRef、shallowReactive、shallowReadonly、unref 等等。
ref
对象采用内部值,returns 是一个反应性和可变对象。通常用于String、Boolean、Number等原始类型单变量
reactive
是一个包装对象,它接受一个对象和 returns 原始对象的反应代理。通常用于 dictionary-structured 类型,例如 JS 对象。
您可以在本文中了解更多关于 ref 与 reactive 的信息: https://dev.to/hirajatamil/must-know-ref-vs-reactive-differences-in-vue-3-composition-api-3bp4