开会员与付费前请必须阅读这篇文章,在首页置顶第一篇:(进站必看本站VIP介绍/购买须知)
本站所有源码均为自动秒发货,默认(百度网盘)
本站所有源码均为自动秒发货,默认(百度网盘)
在 Vue 3 中,ref 和 reactive 是实现响应式数据的核心 API,它们在数据类型支持、访问方式、底层实现及适用场景上存在显著差异。以下是两者的详细对比及适用场景分析:
核心区别
| 特性 | ref |
reactive |
|---|---|---|
| 数据类型支持 | 所有类型(基本类型如 number/string/boolean,以及对象/数组) |
仅对象或数组(如 { count: 0 } 或 [1, 2, 3]) |
| 访问方式 | 在 JavaScript 中需通过 .value 访问或修改值(如 count.value++) |
直接访问或修改属性(如 state.count++) |
| 模板中使用 | 自动解包,无需 .value(如 {{ count }}) |
直接访问属性(如 {{ state.count }}) |
| 重新赋值 | 支持整体替换(如 count.value = 10) |
不支持直接替换整个对象(如 state = { count: 10 } 会丢失响应性) |
| 底层实现 | 通过 RefImpl 类包装值,基本类型会包装成对象,对象类型内部调用 reactive |
基于 ES6 Proxy 劫持对象,拦截属性的读写、新增、删除操作 |
| 响应式追踪 | 单个独立的引用,依赖收集按 .value 触发 |
整个对象及其内部属性统一追踪,依赖收集按属性触发 |
适用场景
ref 的适用场景
- 基本类型数据
- 适用于计数器(如
const count = ref(0))、开关状态(如const isOpen = ref(false))、输入框文本等独立值。 - 示例:
javascript
1const count = ref(0); 2function increment() { 3 count.value++; // 修改值需通过 .value 4} 5
- 适用于计数器(如
- 需要整体替换的对象/数组
- 当需要完全替换一个对象或数组时(如从接口拉取新数据),
ref更灵活。 - 示例:
javascript
1const user = ref({ name: 'Alice', age: 25 }); 2user.value = { name: 'Bob', age: 30 }; // 整体替换保持响应性 3
- 当需要完全替换一个对象或数组时(如从接口拉取新数据),
- 引用 DOM 元素
- 在模板中通过
ref属性挂载 DOM 元素,并在 JavaScript 中访问。 - 示例:
html
1<template> 2 <input ref="inputRef" /> 3</template> 4<script setup> 5import { ref, onMounted } from 'vue'; 6const inputRef = ref(null); 7onMounted(() => { 8 inputRef.value.focus(); // 访问 DOM 元素 9}); 10</script> 11
- 在模板中通过
- 组合式函数返回数据
- 在组合式函数中返回响应式数据时,使用
ref可以确保解构后仍保持响应性(需配合toRefs)。 - 示例:
javascript
1function useCounter() { 2 const count = ref(0); 3 return { count }; // 返回的 count 保持响应性 4} 5
- 在组合式函数中返回响应式数据时,使用
reactive 的适用场景
- 复杂对象或嵌套数据结构
- 适用于表单数据、用户信息、配置对象等关联性强的多字段数据。
- 示例:
javascript
1const form = reactive({ 2 username: '', 3 password: '', 4 remember: false 5}); 6form.username = 'Alice'; // 直接修改属性 7
- 数组操作
- 对数组的增删改查操作(如
push、pop、splice)天然支持响应式。 - 示例:
javascript
1const todos = reactive(['Learn Vue 3', 'Build a project']); 2todos.push('Deploy to production'); // 数组操作保持响应性 3
- 对数组的增删改查操作(如
- 深层嵌套对象
- 对象的嵌套属性也会被自动代理为响应式,无需额外处理。
- 示例:
javascript
1const nestedData = reactive({ 2 user: { 3 profile: { 4 name: 'Alice', 5 address: { city: 'New York' } 6 } 7 } 8}); 9nestedData.user.profile.address.city = 'Beijing'; // 深层修改仍响应式 10
- 模块化状态管理
- 在大型应用中,可以用
reactive创建模块化的状态对象,便于维护和扩展。 - 示例:
javascript
1const store = reactive({ 2 user: { name: 'Jane', loggedIn: false }, 3 settings: { theme: 'dark', notifications: true } 4}); 5function login() { 6 store.user.loggedIn = true; // 修改嵌套属性 7} 8
- 在大型应用中,可以用
性能与最佳实践
- 性能差异:
ref和reactive的性能差异微小,可忽略不计。ref对基本类型进行轻量级劫持,对象类型内部调用reactive;reactive直接通过Proxy代理对象。 - 最佳实践:
- 基本类型用
ref,复杂对象用reactive。 - 解构
reactive对象时,使用toRefs保持响应性。 - 避免在
reactive中嵌套ref(除非明确需要独立引用)。 - 对大型数据集考虑
shallowRef或shallowReactive提升性能。
- 基本类型用