以下是关于 Vue3 中 toReftoRefstoRaw 的详细教程及使用实例:


一、toRef:创建单个属性的响应式引用

作用

将响应式对象的单个属性转换为 ref 对象,保持与原始属性的响应式连接。修改 ref 值会同步更新原对象,反之亦然。

使用场景

  • 需要单独操作对象的某个属性时
  • 传递单个属性到子组件时保持响应性

示例代码

import { reactive, toRef } from 'vue';

const state = reactive({ name: 'Alice', age: 25 });
const nameRef = toRef(state, 'name'); // 将 name 转换为 ref

// 修改 ref 值
nameRef.value = 'Bob';
console.log(state.name); // 输出 'Bob'(原对象同步更新)

二、toRefs:批量解构响应式对象

作用

将整个响应式对象的所有属性转换为普通对象,每个属性都是 ref 引用,避免解构时丢失响应性。

使用场景

  • 解构 reactive 对象后仍需保持响应性
  • 在组合式函数中返回多个响应式属性

示例代码

import { reactive, toRefs } from 'vue';

const state = reactive({ count: 0, message: 'Hello' });
const { count, message } = toRefs(state); // 解构后仍为 ref

// 修改 ref 值
count.value++;
message.value = 'Bonjour';
console.log(state.count); // 输出 1(原对象同步更新)

对比直接解构

// ❌ 错误示例:直接解构会失去响应性
const { count } = state; 
count++; // 视图不会更新

// ✅ 正确示例:使用 toRefs
const { count } = toRefs(state);
count.value++; // 视图更新

三、toRaw:获取原始非代理对象

作用

返回响应式对象(reactivereadonly 创建)的原始非代理版本,修改原始对象不会触发视图更新。

使用场景

  • 需要对比原始数据时
  • 与第三方库交互时避免代理干扰

示例代码

import { reactive, toRaw } from 'vue';

const state = reactive({ data: 'secret' });
const rawState = toRaw(state); // 获取原始对象

// 修改原始对象
rawState.data = 'modified';
console.log(state.data); // 输出 'modified'(响应式对象的值变化)
console.log(rawState === state); // 输出 false(非同一对象)

四、综合对比与注意事项

方法 输入类型 输出类型 响应式保持 典型场景
toRef 响应式对象 + 属性 ref ✔️ 单独操作属性
toRefs 响应式对象 普通对象(含 ref) ✔️ 解构对象或组合式函数返回值
toRaw 响应式对象 原始对象 数据对比、避免副作用

注意事项

  1. 非响应式对象:若对普通对象使用 toRef/toRefs,修改 ref 不会更新视图,但数据会变化。
  2. 性能优化toRaw 可用于处理大型数据,跳过代理转换提升性能。
  3. 深层响应性toRefs 仅处理对象的第一层属性,嵌套对象需手动处理。

五、完整实例演示

<template>
  <div>
    <p>Name: {{ nameRef }}</p>
    <p>Count: {{ count }}</p>
    <button @click="modifyData">修改数据</button>
  </div>
</template>

<script setup>
import { reactive, toRef, toRefs, toRaw } from 'vue';

const state = reactive({
  name: 'Vue3',
  count: 0,
  nested: { key: 'value' }
});

// 使用 toRef
const nameRef = toRef(state, 'name');

// 使用 toRefs
const { count } = toRefs(state);

// 使用 toRaw
const modifyData = () => {
  const raw = toRaw(state);
  raw.nested.key = 'newValue'; // 修改原始对象,不会触发视图更新
  console.log(raw === state); // false
};
</script>