vue3中ref和reactive的区别

ops/2025/3/13 0:58:38/

文章目录

  • 一、核心机制对比
  • 二、底层实现剖析
    • 1. reactive简单实现
    • 2. ref 实现原理
  • 三、实战场景对比
    • 1. 基本类型处理
    • 2. 对象类型处理
    • 3. 数组处理
  • 四、高级特性差异
    • 1. 响应式丢失问题
    • 2. 类型替换场景
  • 五、性能对比分析
  • 六、最佳实践
    • 1. 组合式函数规范
    • 2. 表单处理策略
  • 七、特殊场景处理
    • 1. DOM 引用
    • 2. 第三方库集成
  • 八、总结选择策略
    • 1. 优先使用 ref 的场景
    • 2. 优先使用 reactive 的场景
    • 3. 混合使用
      • 3.1 reactive 嵌套 ref
      • 3.2 ref 嵌套 reactive

一、核心机制对比

特性refreactive
包装对象RefImpl类实现Proxy代理对象
响应式原理通过 .value 的 getter/setter 拦截深度代理对象的属性访问
数据类型支持任意类型(推荐基本类型)仅对象/数组/集合类型
深层响应式自动展开(对象会转为 reactive)默认深层响应
模板自动解包支持(顶层属性自动解包)不支持(需保持对象引用)
TS类型推断Ref 类型包裹原始类型推断

二、底层实现剖析

1. reactive简单实现

const reactive = (target) => {return new Proxy(target, {get(target, key) {// 依赖收集track(target, key)return Reflect.get(target, key)},set(target, key, value, receiver) {const oldValue = target[key]const result = Reflect.set(target, key, value, receiver)if (oldValue !== value) {// 触发更新trigger(target, key)}return result}// 其他拦截操作...})
}
  • 依赖收集(Track):
    • 通过 track 函数将当前正在执行的副作用(effect)与目标对象的属性关联。
    • 使用 WeakMap 存储依赖关系,结构为:
targetMap = WeakMap({target: Map({key: Set(effect1, effect2, ...)})
});
  • 触发更新(Trigger):
    • 当属性变化时,通过 trigger 函数找到所有关联的副作用并执行。

2. ref 实现原理

class RefImpl {constructor(value) {this._value = isObject(value) ? reactive(value) : value;this.dep = new Set(); // 依赖集合}get value() {track(this.dep); // 依赖收集return this._value;}set value(newVal) {if (this._value !== newVal) {this._value = isObject(newVal) ? reactive(newVal) : newVal;trigger(this.dep); // 触发更新}}
}const ref = (value) => new RefImpl(value);
  • 依赖收集与触发更新:
    • 每个 ref 实例内部维护一个 dep 集合(类似 reactive 的依赖管理)。
    • 当通过 .value 访问时,触发 track;修改时触发 trigger。
  • 关键设计:
    • 值类型包装: 通过 .value 访问值,解决基本类型无法被 Proxy 直接代理的问题。
    • 自动解包: 在模板中使用 ref 时,Vue 会自动解包(无需写 .value)。

三、实战场景对比

1. 基本类型处理

// 正确用法
const count = ref(0) // ✅ 自动类型推断为 Ref<number>// 错误尝试
const count = reactive(0) // ❌ 参数必须是对象类型

2. 对象类型处理

// ref 处理对象(自动解包)
const user = ref({name: 'John',address: {city: 'New York'}
})// 等效于 reactive 写法
const user = reactive({name: 'John',address: reactive({city: 'New York'})
})// 访问方式对比
console.log(user.value.name) // ref 需要 .value
console.log(user.name)        // reactive 直接访问

3. 数组处理

// ref 数组
const listRef = ref([1, 2, 3])
listRef.value.push(4) // ✅ 正确修改方式// reactive 数组
const listReactive = reactive([1, 2, 3])
listReactive.push(4) // ✅ 直接操作

四、高级特性差异

1. 响应式丢失问题

// reactive 的解构问题
const state = reactive({ count: 0 })
const { count } = state // ❌ 失去响应性// ref 的 解构
const countRef = ref(0)
const count = countRef // ❌ 仍需通过 .value 访问// 正确解构方式(reactive)
const state = reactive({ count: 0 })
const countRef = toRef(state, 'count') // ✅ 保持响应

2. 类型替换场景

// ref 允许整体替换
const data = ref({ items: [] })
data.value = fetchData() // ✅ 响应式更新// reactive 需保持引用
const data = reactive({ items: [] })
Object.assign(data, fetchData()) // ✅ 正确方式
data = fetchData() ❌ 破坏响应性

五、性能对比分析

操作ref(基本类型)reactive(对象)差异原因
创建速度★★★★☆★★★☆☆Proxy初始化成本较高
属性访问★★★★☆★★★☆☆Proxy拦截带来额外开销
深层监听★☆☆☆☆★★★★★Proxy自动深度代理
内存占用较低较高Proxy对象占用更多内存

六、最佳实践

1. 组合式函数规范

// 推荐返回 ref 保持灵活性
function useCounter(initial = 0) {const count = ref(initial)return { count }
}// 复杂状态使用 reactive + toRefs
function useUser() {const state = reactive({name: '',age: ''})return { ...toRefs(state) }
}

2. 表单处理策略

// 复杂表单使用 reactive
const form = reactive({username: '',password: '',preferences: {theme: 'light',notifications: true}
})// 单个表单字段使用 ref
const searchQuery = ref('')

七、特殊场景处理

1. DOM 引用

获取元素对象或者组件对象只能使用 ref ,reactive无法处理 DOM 引用

<script setup>javascript">const inputRef = ref(null)
</script><templete><div ref="inputRef"></div>
</templete>

2. 第三方库集成

// 需要保持引用的场景
const chartInstance = ref(null)// 响应式配置对象
const options = reacitve({title: { text: '热销' },series: [ ... ]
})

八、总结选择策略

1. 优先使用 ref 的场景

  • 基本类型值(string/number/boolean)
  • 需要模板自动解包
  • 可能被整体替换的对象
  • 需要传递给composable函数的参数

2. 优先使用 reactive 的场景

  • 复杂嵌套对象
  • 需要深度响应式监听
  • 表单/配置对象等结构化数据
  • 需要直接操作集合类型(Map/Set)

3. 混合使用

3.1 reactive 嵌套 ref

const state = reactive({count: ref(0), // 基础类型 ref ,自动解包user: ref<User>({ name: '' }) // 对象类型 ref ,自动解包
})
  • 行为特点: Vue 会自动解包嵌套在 reactive 中的 ref,访问时无需 .value
state.count++ // 直接操作数字(等价于 state.count.value++)
state.user.name = 'john' // 直接操作对象(等价于 state.user.value.name)
  • 适用场景
    • 混合响应式类型: 当 reactive 对象需要包含基础类型 + 对象类型的混合数据时,用 ref 统一包裹,享受自动解包特性。
    • 外部数据注入: 当某个属性需要从外部接收 ref 类型时(如组合式函数返回的 ref),直接将其嵌入 reactive 对象。

3.2 ref 嵌套 reactive

const complexRef = ref({data: reactive({ /*...*/ }), // 嵌套 reactive 对象status: 'loading'  // 普通属性(非响应式)
})
  • 行为特点:
    • 层级访问: 需要 .value 访问容器内内容
    • 响应式范围:
      • complexRef.value.data 是响应式对象(reactive 创建)
      • complexRef.value.status 是普通字符串(非响应式)
complexRef.value.data.key = "value";  // 直接修改 reactive 对象
complexRef.value.status = "success";  // 修改普通属性(非响应式)
  • 适用场景:
    • 整体替换响应式对象 :如果需要完全替换整个响应式对象,用 ref 包裹可以保持引用。
    • 组合非响应式数据: 当需要混合响应式和非响应式数据时,ref 作为容器更灵活。
complexRef.value = {  // 替换整个对象(触发响应式更新)data: reactive({ /*...*/ }),status: 'success'
};

http://www.ppmy.cn/ops/165275.html

相关文章

oracle goldengate 各版本支持的源端和目标端的数据库版本列表

# oracle goldengate 各版本支持的源端和目标端的数据库版本列表 GoldenGate Supported System Configurations| Oraclehttps://www.oracle.com/integration/goldengate/certifications/

[Web]ServletContext域(Application)

简介 Web应用的Application域的实现是通过ServletContext对象实现的。整个Web应用程序的所有资源共享这个域。生命周期与Web应用程序相同&#xff0c;即当前Web应用程序启动时&#xff08;以服务器视角而非访客视角&#xff09;出生&#xff0c;Web应用服务程序关闭时停止。 通…

深入浅出Bearer Token:解析工作原理及其在Vue、Uni-app与Java中的实现Demo

目录 前言1. 基本知识2. Demo3. 实战 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. 基本知识 Bearer Token是一种基于Token的认证机制&#xff0c;用于在HTTP请求中传递用户的身份信息 应用于RESTful A…

基于PyTorch的深度学习6——可视化工具Tensorboard

先安装tensorflow&#xff08;CPU或GPU版&#xff09;​&#xff0c;然后安装tensorboardX&#xff0c;在命令行运行以下命令即可。 pip install tensorboardX 使用tensorboardX的一般步骤如下所示。 1)导入tensorboardX&#xff0c;实例化SummaryWriter类&#xff0c;指明记…

[项目]基于FreeRTOS的STM32四轴飞行器: 四.LED控制

基于FreeRTOS的STM32四轴飞行器: 四.LED控制 一.配置Com层二.编写驱动 一.配置Com层 先在Com_Config.h中定义灯位置的枚举类型&#xff1a; 之后定义Led的结构体&#xff1a; 定义飞行器状态&#xff1a; 在Com_Config.c中初始化四个灯&#xff1a; 在Com_Config.h外部声明…

Trae AI 开发工具使用手册

这篇手册将介绍 Trae 的基本功能、安装步骤以及使用方法&#xff0c;帮助开发者快速上手这款工具。 Trae AI 开发工具使用手册 Trae 是字节跳动于 2025 年推出的一款 AI 原生集成开发环境&#xff08;IDE&#xff09;&#xff0c;旨在通过智能代码生成、上下文理解和自动化任务…

YashanDB认证,YCA证书认证教程,免费证书,内含真题考试题库及答案——五分钟速成

目录 一.账号及平台注册登录流程 二.登录进行设备调试核验 三.考试&#xff08;考完获取分数&#xff09; 四.获取证书 五.题库及答案 一.账号及平台注册登录流程 1-点击这里进行账号注册&#xff08;首次学习必须先注册&#xff0c;有账号之后可以直接在2号链接登录&#…

[项目]基于FreeRTOS的STM32四轴飞行器: 七.遥控器按键

基于FreeRTOS的STM32四轴飞行器: 七.遥控器 一.遥控器按键摇杆功能说明二.摇杆和按键的配置三.按键扫描 一.遥控器按键摇杆功能说明 两个手柄四个ADC。 左侧手柄&#xff1a; 前后推为飞控油门&#xff0c;左右推为控制飞机偏航角。 右侧手柄&#xff1a; 控制飞机飞行方向&a…