1. ref
:创建独立的响应式引用
- 用途 :为基本类型(
string
、number
、boolean
)或对象创建一个响应式引用。
核心特性
- 返回值 :返回一个包含
.value
属性的响应式对象。 - 响应式原理 :通过
Object.defineProperty
或 Proxy 实现值的跟踪。 - 自动解包 :在模板中使用时无需
.value
,但在 JavaScript 逻辑中需要。
js
import { ref } from 'vue';
const count = ref(0); // 基本类型
const user = ref({ name: 'Alice' }); // 对象
count.value++; // 修改值
user.value.name = 'Bob'; // 修改对象属性(自动触发响应)
2. toRef
:将响应式对象的属性转为单个ref
- 用途 :从
reactive
创建的响应式对象中提取某个属性,生成一个与之保持连接的ref
。
核心特性
- 返回值 :返回一个与源属性 保持响应式连接 的
ref
。 - 响应式原理 :直接代理原对象的属性,修改
ref
或原对象会互相影响。
适用场景:需要将某个属性单独传递并保持响应性。
js
import { reactive, toRef } from 'vue';
const state = reactive({ name: 'Alice', age: 30 });
const nameRef = toRef(state, 'name');
nameRef.value = 'Bob'; // 修改 ref 值
console.log(state.name); // 'Bob'(源对象同步更新)
3. toRefs
:将响应式对象的所有属性转为 ref
- 用途 :将
reactive
对象转换为普通对象,但每个属性都是ref
,保持响应性。
核心特性
-
返回值 :返回一个普通对象,每个属性都是与原对象属性绑定的
ref
。 -
响应式原理 :为每个属性创建
toRef
,确保解构后仍保持响应性。 -
适用场景 :在返回响应式对象时,结合解构语法保持响应性(如从
setup
返回数据)。
js
import { reactive, toRefs } from 'vue';
const state = reactive({ name: 'Alice', age: 30 });
const { name, age } = toRefs(state); // 解构为 ref
name.value = 'Bob'; // 修改 ref
console.log(state.name); // 'Bob'(源对象同步更新)
4. 对比表格
特性 | ref |
toRef |
toRefs |
---|---|---|---|
用途 | 创建新的响应式引用 | 将响应式对象的某个属性转为 ref | 将响应式对象的所有属性转为 ref |
返回值 | 单个 ref 对象 |
单个 ref 对象 |
包含多个 ref 的普通对象 |
数据源 | 任意值(基本类型或对象) | 必须来自 reactive 对象 |
必须来自 reactive 对象 |
响应性连接 | 独立响应式引用 | 与原对象属性保持双向绑定 | 与原对象所有属性保持双向绑定 |
解构支持 | 不直接支持解构 | 不直接支持解构 | 支持解构并保持响应性 |
自动解包 | 模板中自动解包(无需 .value ) |
需手动使用 .value |
需手动使用 .value |
5. 常见误区与最佳实践
1. ref
与 toRef
的误用
- 错误示例:
js
const state = reactive({ count: 0 });
const countRef = ref(state.count); // ❌ 失去响应性!
ref(state.count)
会复制 state.count
的初始值,但后续修改 state.count
不会影响 countRef
。
- 正确做法 :使用
toRef
保持连接:
js
const countRef = toRef(state, 'count'); // ✅
2. 解构响应式对象
- 错误示例:
js
const state = reactive({ count: 0 });
const { count } = state; // ❌ 解构后失去响应性!
- 正确做法 :使用
toRefs
:
js
const { count } = toRefs(state); // ✅
3. 组合式函数的返回值
- 最佳实践 :在组合式函数中返回
toRefs(reactiveObject)
,确保调用方可安全解构:
js
function useCounter() {
const state = reactive({ count: 0 });
const increment = () => { state.count++ };
return { ...toRefs(state), increment }; // ✅
}
6. 总结
- 避免滥用
toRefs
:如果不需要解构整个对象,优先使用toRef
按需提取属性。 ref
与reactive
的选择 :简单数据用ref
,复杂对象用reactive
。- 响应性丢失 :直接解构
reactive
对象会失去响应性,必须通过toRefs
解构。