vue-22(理解组合式 API:setup、ref、reactive)
Vue.js 中的组合式 API 代表了我们构建和组织组件方式的重大转变。它为传统的选项式 API 提供了一种更灵活、更强大的替代方案,尤其适用于复杂的应用程序。本章将深入探讨组合式 API 的核心概念:setup
函数、ref
和reactive
,为你构建更可维护、更可重用的 Vue 组件打下坚实的基础。我们将探索这些元素如何协同工作,以实现更功能化、更可组合的组件逻辑。
理解 setup
函数
setup
函数是 Vue 组件中使用 Composition API 的入口点。它用于定义响应式数据、计算属性、方法和生命周期钩子。与 Options API 不同,在 Options API 中这些元素定义在组件定义的单独部分中,而 setup
函数允许你以更逻辑和连贯的方式组织它们。
setup
的作用
setup
函数充当组件模板与其底层逻辑之间的桥梁。它在组件创建 之前 执行,并提供对组件的 props
和 context
的访问。setup
函数必须返回一个包含你希望提供给模板的数据、方法和计算属性的对象。
示例:基本的 setup
函数
import { ref } from 'vue';export default {props: {initialCount: {type: Number,default: 0}},setup(props, context) {// 使用“ref”创建一个反应变量const count = ref(props.initialCount);// 定义一个方法来增加计数const increment = () => {count.value++;};// 将反应变量和方法暴露给模板return {count,increment};},template: `<div><p>Count: {{ count }}</p><button @click="increment">Increment</button></div>`
};
在这个例子中:
- 我们从 Vue 导入
ref
函数。 setup
函数接收props
和context
作为参数。- 我们使用
ref
创建一个响应式变量count
,并使用initialCount
prop 的值进行初始化。 - 我们定义一个方法
increment
,用于增加count
的值。注意,我们通过.value
访问ref
的值。 - 我们返回一个包含
count
和increment
的对象,使其在模板中可用。 - 模板显示
count
的当前值,并提供一个按钮来增加它。
setup
参数:props
和 context
setup
函数接收两个参数:
props
: 一个包含组件属性的对象。需要注意的是,props
对象是响应式的。如果父组件更新了属性,setup
中的props
对象将自动更新。context
: 一个提供访问组件上下文的对象。它暴露了三个属性:attrs
: 一个包含组件非属性属性的对象(相当于 Options API 中的$attrs
)。slots
: 一个包含组件插槽的对象(相当于 Options API 中的$slots
)。emit
: 一个允许你从组件中发出自定义事件的函数(在选项 API 中相当于$emit
)。
示例:使用 context.emit
import { ref } from 'vue';export default {setup(props, context) {const count = ref(0);const increment = () => {count.value++;// Emit a custom event when the count is incrementedcontext.emit('increment', count.value);};return {count,increment};},template: `<div><p>Count: {{ count }}</p><button @click="increment">Increment</button></div>`
};
在这个例子中,我们使用 context.emit
来在每次调用 increment
方法时发出一个名为 increment
的自定义事件。事件负载是 count
的新值。
ref
: 创建响应式引用
ref
函数是 Composition API 的核心部分。它允许你创建对基本值(数字、字符串、布尔值)和复杂数据类型(对象、数组)的响应式引用。当 ref
的值发生变化时,Vue 会自动更新 DOM 以反映新值。
如何 ref
工作
ref
函数接受一个参数:引用的初始值。它返回一个具有 .value
属性的对象,该属性保存当前值。访问或修改 ref
的值需要使用 .value
属性。
示例:使用 ref
与原始值
import { ref } from 'vue';export default {setup() {const message = ref('Hello, Vue!');const updateMessage = () => {message.value = 'Goodbye, Vue!';};return {message,updateMessage};},template: `<div><p>{{ message }}</p><button @click="updateMessage">Update Message</button></div>`
};
在这个例子中:
- 我们创建一个名为
ref
的message
,初始值为"Hello, Vue!"。 - 我们定义一个名为
updateMessage
的方法,该方法将message
的值更改为"Goodbye, Vue!"。 - 模板显示
message
的当前值。当按钮被点击时,updateMessage
被调用,模板会自动更新以显示新消息。
示例:使用 ref
与复杂数据类型
import { ref } from 'vue';export default {setup() {const user = ref({name: 'John Doe',age: 30});const updateUser = () => {user.value.name = 'Jane Doe';user.value.age = 25;};return {user,updateUser};},template: `<div><p>Name: {{ user.name }}</p><p>Age: {{ user.age }}</p><button @click="updateUser">Update User</button></div>`
};
在这个例子中:
- 我们创建一个名为
ref
的user
引用,其初始值是一个包含name
和age
属性的对象。 - 我们定义一个名为
updateUser
的方法,用于更新user
对象中的name
和age
属性。 - 模板显示
user
对象的name
和age
属性。当按钮被点击时,调用updateUser
,模板会自动更新以显示新的用户信息。
何时使用 ref
使用 ref
当你需要创建一个单一值的响应式引用,无论是基本类型还是复杂的数据类型。当你需要跟踪组件中单个值的变化时,它特别有用。
reactive
: 创建响应式对象
reactive
函数是 Composition API 的另一个重要部分。它允许你创建响应式对象。与 ref
不同,ref
创建一个值的响应式 引用 ,reactive
创建一个响应式的 对象 。响应式对象属性的变化会被 Vue 自动跟踪,并且 DOM 会相应更新。
reactive
的工作原理
reactive
函数接受一个普通的 JavaScript 对象作为参数,并返回该对象的响应式代理。然后你可以直接访问和修改响应式对象的属性,而无需像使用 ref
那样使用 .value
属性。
示例:使用 reactive
import { reactive } from 'vue';export default {setup() {const state = reactive({name: 'John Doe',age: 30});const updateState = () => {state.name = 'Jane Doe';state.age = 25;};return {state,updateState};},template: `<div><p>Name: {{ state.name }}</p><p>Age: {{ state.age }}</p><button @click="updateState">Update State</button></div>`
};
在这个例子中:
- 我们使用
reactive
函数创建一个响应式对象state
。 - 我们定义一个方法
updateState
,用于更新state
对象的name
和age
属性。 - 模板显示
state
对象的name
和age
属性。当按钮被点击时,调用updateState
,模板会自动更新以显示新的状态信息。
深度响应式
reactive
函数提供深度响应式功能。这意味着在响应式对象中的嵌套属性的变化也会被 Vue 跟踪。
示例:深度响应式
import { reactive } from 'vue';export default {setup() {const state = reactive({user: {name: 'John Doe',address: {city: 'New York'}}});const updateCity = () => {state.user.address.city = 'Los Angeles';};return {state,updateCity};},template: `<div><p>Name: {{ state.user.name }}</p><p>City: {{ state.user.address.city }}</p><button @click="updateCity">Update City</button></div>`
};
在这个例子中,即使 city
是 state
对象中的嵌套属性,对它的修改仍然会被 Vue 追踪,并且模板会相应地更新。
reactive
的局限性
-
仅适用于对象:
reactive
函数仅适用于普通的 JavaScript 对象。它不能用于数字、字符串或布尔值等原始值。对于这些值,你应该使用ref
。 -
重新赋值导致的响应性丢失: 如果你重新赋值一个响应式对象,你会丢失响应性。例如:
import { reactive } from 'vue';export default {setup() {const state = reactive({ count: 0 });const resetState = () => {// Reactivity is lost here!state = { count: 0 };};return { state, resetState };},template: '<button @click="resetState">Reset</button>' };
在这种情况下,
state
在重新赋值后不再具有响应性。为了避免这种情况,始终修改响应式对象的属性,而不是重新赋值对象本身。
何时使用 reactive
当你需要创建具有多个属性的反应式对象时,使用 reactive
。当你有一个复杂的数据结构需要追踪变化时,它特别有用。
ref
与 reactive
:选择合适的工具
ref
和 reactive
都用于在 Composition API 中创建反应式数据,但它们有不同的使用场景。以下是它们的主要区别总结:
特性 | ref | reactive |
---|---|---|
数据类型 | 可与原始类型和对象一起使用 | 仅适用于对象 |
访问值 | 使用 .value 来访问/修改 | 直接访问/修改属性 |
响应性 | 创建一个响应式_引用_ | 创建一个响应式_对象_ |
用例 | 单个值、基本类型 | 具有多个属性的对象 |
一般来说,使用 ref
表示单个值和基本类型,使用 reactive
表示具有多个属性的对象。