1.ref
ref
响应式 API,用于创建响应式数据。 函数接收一个初始值作为参数,并返回一个响应式的引用对象(Ref 对象)。这个对象有一个 .value
属性,用于访问和修改其内部的值。
javascript
import { ref } from 'vue'
// 创建一个响应式的数字
const count = ref(0)
// 访问值
console.log(count.value) // 输出: 0
// 修改值
count.value = 1
console.log(count.value) // 输出: 1
不同数据类型的处理
-
基本类型 (number、string、boolean 等):
ref
会将其包装为 Ref 对象,必须通过.value
访问和修改 -
对象类型 (object、array 等):
ref
内部会自动调用reactive
进行处理,所以修改对象属性时不需要.value
ini// 基本类型 const message = ref('Hello') message.value = 'Hello Vue3' // 需要 .value // 对象类型 const user = ref({ name: '张三', age: 20 }) user.value.name = '李四' // 修改整个对象需要 .value user.age = 21 // 修改对象属性不需要 .value
模板中使用
ref
创建的响应式数据时,Vue 会自动解包(不需要写 .value
)
xml
<template>
<div>
<p>计数: {{ count }}</p>
<button @click="count++">增加</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
在响应式对象
javascript
import { ref, reactive } from 'vue'
const count = ref(0)
const data = reactive({
count // 这里会自动解包
})
console.log(data.count) // 0,不需要 .value
data.count = 1
console.log(count.value) // 1,原 ref 也会同步更新
与 reactive 的区别
ref
可以处理基本类型,reactive
只能处理对象类型ref
需要通过.value
访问值(模板中除外),reactive
直接访问属性ref
返回的是 Ref 对象,reactive
返回的是 Proxy 对象
2.toRaw
Vue3 的响应式系统通过 Proxy
(代理)实现:当用 reactive()
或 ref()
创建响应式对象时,Vue 会生成一个代理对象(而非直接修改原始数据),这个代理会追踪数据访问和修改,从而触发视图更新或依赖执行。
toRaw
的作用就是穿透这个代理,返回被代理的原始对象 。
javascript
import { reactive, toRaw } from 'vue'
const original = { name: 'test' }
const reactiveObj = reactive(original) // 创建响应式代理
console.log(reactiveObj === original) // false(reactiveObj 是代理)
console.log(toRaw(reactiveObj) === original) // true(toRaw 返回原始对象)
toRaw
主要用于需要操作原始数据,且不希望触发响应式更新或避免代理带来的性能开销的场景
运用场景
1.避免不必要的视图更新(中间状态处理)
当执行复杂业务逻辑(如数据计算、批量处理)时,可能需要临时修改数据,但这些中间修改不需要立即触发视图更新(避免界面频繁闪烁或无效渲染)
php
import { reactive, toRaw } from 'vue'
const formData = reactive({ name: '', age: 0 })
// 复杂校验逻辑:临时修改数据但不触发更新
function validate() {
const rawForm = toRaw(formData) // 获取原始数据
// 临时修改原始数据(不会触发视图更新)
rawForm.age = rawForm.age || 18 // 补默认值
// ... 其他校验逻辑
// 校验完成后,若需要更新响应式数据,可再同步回去
formData.age = rawForm.age
}
2.提高复杂操作的性能(减少代理开销)
响应式代理的追踪逻辑会带来少量性能损耗,对于频繁读写的复杂数据操作(如大数据量循环、深拷贝、序列化),直接操作原始数据可显著提升性能。
javascript
import { reactive, toRaw } from 'vue'
import { cloneDeep } from 'lodash'
const bigData = reactive({ list: [...Array(10000).keys()] }) // 大数据量响应式对象
// 直接深拷贝响应式对象(会处理代理,性能低)
const slowCopy = cloneDeep(bigData)
// 先转原始对象再拷贝(性能更高)
const rawData = toRaw(bigData)
const fastCopy = cloneDeep(rawData)
3.临时存储原始状态(用于对比或回滚)
kotlin
import { reactive, toRaw } from 'vue'
const data = reactive({ value: 0 })
// 记录事务开始前的原始状态
const snapshot = toRaw(data)
// 执行事务(修改响应式数据)
data.value = 100
// 回滚:用原始快照覆盖当前数据
Object.assign(data, snapshot)
仅对 reactive
创建的对象有效 :toRaw
用于 reactive
生成的响应式对象;对于 ref
对象,需先访问 .value
再使用 toRaw
(因为 ref
的响应式代理在 .value
上):
csharp
import { ref, toRaw } from 'vue'
const countRef = ref(0)
const rawCount = toRaw(countRef.value) // 正确:获取 ref.value 的原始值
修改原始对象不会触发响应式更新 :toRaw
返回的原始对象与响应式代理指向同一内存地址,但修改原始对象不会触发视图更新或依赖执行(需手动同步到响应式对象才会更新)