第6章:组合式API
第14节:响应式基础
6.14.1 ref函数深度解析
ref是Vue 3组合式API中用于创建响应式数据的核心函数之一。它可以将基本类型或对象类型转换为响应式数据。
基本用法
import { ref } from 'vue'
// 创建基本类型的响应式数据
const count = ref(0)
const message = ref('Hello')
const isActive = ref(true)
// 创建对象类型的响应式数据
const user = ref({
name: '张三',
age: 25
})访问和修改ref数据
使用ref创建的响应式数据需要通过.value属性来访问和修改:
// 访问数据
console.log(count.value) // 0
console.log(message.value) // Hello
console.log(user.value.name) // 张三
// 修改数据
count.value++ // 1
message.value = 'World' // World
user.value.age = 26 // 26ref的响应式原理
- 对于基本类型,
ref会将其包装成一个包含.value属性的对象 - 对于对象类型,
ref内部会调用reactive函数将其转换为响应式代理 - 当访问或修改
.value属性时,Vue会自动追踪依赖并触发更新
ref在模板中的使用
在模板中使用ref创建的数据时,不需要使用.value,Vue会自动解包:
<template>
<div>
<p>count: {{ count }}</p> <!-- 自动解包,不需要.count.value -->
<button @click="count++">增加</button>
<p>用户名: {{ user.name }}</p> <!-- 自动解包 -->
<button @click="user.age++">增加年龄</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
const user = ref({ name: '张三', age: 25 })
</script>6.14.2 reactive函数与响应式对象
reactive函数用于创建对象类型的响应式数据。它返回一个响应式代理对象。
基本用法
import { reactive } from 'vue'
// 创建响应式对象
const state = reactive({
count: 0,
message: 'Hello',
user: {
name: '张三',
age: 25
},
items: [1, 2, 3]
})访问和修改reactive数据
使用reactive创建的响应式数据可以直接访问和修改,不需要.value:
// 访问数据
console.log(state.count) // 0
console.log(state.user.name) // 张三
console.log(state.items[0]) // 1
// 修改数据
state.count++ // 1
state.message = 'World' // World
state.user.age = 26 // 26
state.items.push(4) // [1, 2, 3, 4]reactive的响应式原理
reactive使用ES6的Proxy API创建响应式代理- 自动处理嵌套对象,为所有嵌套属性创建响应式代理
- 支持数组索引和长度变化的检测
- 支持新增和删除属性的检测
reactive的局限性
- 只支持对象类型:不能用于基本类型(number、string、boolean等)
- 直接解构会丢失响应性:直接解构reactive对象会导致失去响应性
- 不能替换整个对象:替换整个reactive对象会导致失去响应性
6.14.3 ref vs reactive选择指南
何时使用ref
- 基本类型数据:
ref是创建基本类型响应式数据的唯一选择 - 需要解构的数据:
ref解构后仍能保持响应性 - 需要替换整个对象:
ref可以直接替换.value - 在组合式函数中返回数据:
ref更适合在组合式函数中返回,因为它可以保持响应性
何时使用reactive
- 复杂对象:对于包含多个属性的复杂对象,
reactive使用起来更简洁 - 不需要解构的数据:如果不需要解构对象,
reactive的语法更简洁 - 组件内部状态管理:对于组件内部的复杂状态,
reactive可以提供更清晰的结构
对比表格
| 特性 | ref | reactive |
|---|---|---|
| 支持的类型 | 基本类型和对象类型 | 仅对象类型 |
| 访问方式 | 通过.value访问 |
直接访问 |
| 解构支持 | 解构后仍保持响应性 | 直接解构会丢失响应性 |
| 替换对象 | 可以直接替换.value |
不能直接替换整个对象 |
| 模板使用 | 自动解包,不需要.value |
直接使用 |
| 组合式函数返回 | 推荐使用 | 不推荐,解构会丢失响应性 |
示例:ref和reactive的选择
// 基本类型数据,使用ref
const count = ref(0)
const message = ref('Hello')
// 复杂对象,使用reactive
const user = reactive({
name: '张三',
age: 25,
address: {
city: '北京',
district: '朝阳区'
}
})
// 需要解构的数据,使用ref
const config = ref({
theme: 'light',
fontSize: 16
})
// 解构后仍保持响应性
const { theme, fontSize } = config.value6.14.4 toRef和toRefs响应式解构
当需要解构reactive对象时,可以使用toRef或toRefs函数来保持响应性。
toRef函数
toRef函数用于将reactive对象的单个属性转换为ref:
import { reactive, toRef } from 'vue'
const state = reactive({
count: 0,
message: 'Hello'
})
// 将单个属性转换为ref
const countRef = toRef(state, 'count')
const messageRef = toRef(state, 'message')
// 访问和修改
console.log(countRef.value) // 0
countRef.value++ // 1
console.log(state.count) // 1 (同步更新)toRefs函数
toRefs函数用于将reactive对象的所有属性转换为ref,并返回一个新的对象:
import { reactive, toRefs } from 'vue'
const state = reactive({
count: 0,
message: 'Hello',
user: {
name: '张三',
age: 25
}
})
// 将所有属性转换为ref
const refs = toRefs(state)
console.log(refs.count.value) // 0
console.log(refs.message.value) // Hello
// 解构后仍保持响应性
const { count, message, user } = toRefs(state)
console.log(count.value) // 0
count.value++ // 1
console.log(state.count) // 1 (同步更新)toRef和toRefs的特点
- 保持响应性:转换后的
ref数据与原reactive对象保持同步 - 浅转换:
toRefs只转换对象的顶层属性,嵌套对象不会被转换 - 不创建新数据:
toRef和toRefs不会创建新的数据副本,而是创建对原数据的引用
示例:在组合式函数中使用toRefs
// useCounter.js
import { reactive, toRefs } from 'vue'
export function useCounter() {
const state = reactive({
count: 0,
doubleCount: 0
})
function increment() {
state.count++
state.doubleCount = state.count * 2
}
function decrement() {
state.count--
state.doubleCount = state.count * 2
}
// 使用toRefs转换后返回,保持响应性
return {
...toRefs(state),
increment,
decrement
}
}在组件中使用:
<template>
<div>
<p>count: {{ count }}</p>
<p>doubleCount: {{ doubleCount }}</p>
<button @click="increment">增加</button>
<button @click="decrement">减少</button>
</div>
</template>
<script setup>
import { useCounter } from './useCounter'
// 解构后仍保持响应性
const { count, doubleCount, increment, decrement } = useCounter()
</script>总结
Vue 3的组合式API提供了ref和reactive两个核心函数来创建响应式数据:
- **
ref**:适用于基本类型和需要解构的数据,使用.value访问,模板中自动解包 - **
reactive**:适用于复杂对象,直接访问属性,不能直接解构 - **
toRef和toRefs**:用于将reactive对象的属性转换为ref,保持解构后的响应性
选择使用ref还是reactive取决于具体的使用场景:
- 对于基本类型,使用
ref - 对于复杂对象,如果不需要解构,使用
reactive - 如果需要解构对象,使用
ref或者结合toRefs使用reactive
在下一节中,我们将学习组合式API中的计算属性与侦听器。