当前位置: 首页 > news >正文

前端八股3---ref和reactive

目录

  • 一、核心区别速览
  • 二、代码演示
  • 1. 数据类型不同
  • 2. 访问方式不同
  • 3. 重新赋值的区别(重要!)
  • 4. 解构的区别
  • 三、底层实现原理
  • reactive 的实现
  • ref 的实现(简化版)
  • 四、使用场景建议
  • 什么时候用 reactive?
  • 什么时候用 ref?
  • 五、常见误区与注意点
  • 误区1:reactive 的对象可以直接赋值
  • 误区2:ref 在模板中需要 .value
  • 误区3:ref 传入对象和 reactive 的关系
  • 六、面试回答模板(满分答案)

一、核心区别速览

对比维度reactiveref
数据类型只能代理对象/数组可以代理任意类型(基本类型 + 对象)
底层实现直接使用Proxy对象用reactive,基本类型用 getter/setter
访问方式直接访问state.count需要通过.valuecount.value
模板中使用直接使用自动解包,不需要.value
重新赋值❌ 会丢失响应式✅ 保持响应式
解构❌ 会丢失响应式✅ 用toRefs解构

二、代码演示

1. 数据类型不同

import { reactive, ref } from 'vue'; // reactive:只能用于对象/数组 const state = reactive({ count: 0 }); // ✅ const arr = reactive([1, 2, 3]); // ✅ const num = reactive(0); // ❌ 警告:reactive 不能用于基本类型 // ref:可以用于任意类型 const count = ref(0); // ✅ 基本类型 const user = ref({ name: '张三' }); // ✅ 对象 const list = ref([1, 2, 3]); // ✅ 数组

2. 访问方式不同

const state = reactive({ count: 0 }); state.count++; // 直接访问 const count = ref(0); count.value++; // 需要通过 .value // 但在模板中,ref 会自动解包 // <template> // {{ count }} ← 不需要 .value // </template>

3. 重新赋值的区别(重要!)

// ❌ reactive:重新赋值会丢失响应式 let state = reactive({ count: 0 }); state = { count: 1 }; // 丢失响应式!state 不再是代理对象 // ✅ ref:重新赋值保持响应式 let count = ref(0); count.value = 1; // 响应式还在 count = ref(10); // 重新赋值整个 ref,仍然响应式

4. 解构的区别

// ❌ reactive:解构会丢失响应式 const state = reactive({ count: 0, name: '张三' }); const { count, name } = state; count++; // 不会触发视图更新,只是普通变量 // ✅ 解决方案:使用 toRefs const { count, name } = toRefs(state); count.value++; // 保持响应式 // ✅ ref:单独使用没问题 const count = ref(0); let myCount = count; // 直接赋值引用,保持响应式 myCount.value++; // 会触发更新

三、底层实现原理

reactive 的实现

function reactive(target) { // 只处理对象类型 if (!isObject(target)) { console.warn('reactive 只能用于对象'); return target; } return new Proxy(target, { get(target, key, receiver) { const res = Reflect.get(target, key, receiver); // 依赖收集 track(target, key); // 懒代理:如果返回值是对象,递归代理 if (isObject(res)) { return reactive(res); } return res; }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); // 触发更新 trigger(target, key); return result; } }); }

ref 的实现(简化版)

function ref(value) { // 创建一个对象,带上 .value 属性 const refObject = { _value: value, get value() { // 收集依赖 track(refObject, 'value'); return this._value; }, set value(newVal) { this._value = newVal; // 触发更新 trigger(refObject, 'value'); } }; // 如果传入的是对象,用 reactive 包装 if (isObject(value)) { refObject._value = reactive(value); } return refObject; }

关键点:

  • ref本质是创建了一个有.value属性的对象

  • 基本类型:通过 getter/setter 实现响应式

  • 对象类型:内部调用reactive处理


四、使用场景建议

什么时候用 reactive?

// ✅ 适合:数据结构明确、属性会变化的对象 const state = reactive({ user: { name: '张三', age: 18 }, list: [1, 2, 3] }); // ✅ 适合:表单数据 const form = reactive({ username: '', password: '', email: '' });

什么时候用 ref?

// ✅ 适合:基本类型数据 const count = ref(0); const message = ref(''); const isLoading = ref(false); // ✅ 适合:需要整体替换的数据 const user = ref(null); // 后来获取数据后整体赋值 user.value = { name: '张三', age: 18 }; // ✅ 适合:不确定类型的数据 const data = ref(null); // 可能是对象、数组、基本类型

五、常见误区与注意点

误区1:reactive 的对象可以直接赋值

// ❌ 错误 let state = reactive({ count: 0 }); state = { count: 1 }; // 丢失响应式 // ✅ 正确:修改属性,不要重新赋值 state.count = 1; // ✅ 或者用 Object.assign Object.assign(state, { count: 1 });

误区2:ref 在模板中需要 .value

// ❌ 错误理解 // <template>{{ count.value }}</template> ← 不需要! // ✅ 正确 // <template>{{ count }}</template> ← 自动解包

误区3:ref 传入对象和 reactive 的关系

const objRef = ref({ name: '张三' }); // objRef.value 实际上是一个 reactive 代理对象 console.log(objRef.value === reactive({ name: '张三' })); // false // 但效果相同,都是响应式的

六、面试回答模板(满分答案)

问:reactive 和 ref 的区别是什么?

回答:

主要有以下几点区别:

  1. 数据类型reactive只能代理对象和数组,ref可以代理任意类型(包括基本类型)。

  2. 底层实现reactive直接使用Proxy实现响应式;ref内部创建一个带有.value属性的对象,基本类型通过 getter/setter 实现,对象类型则内部调用reactive

  3. 访问方式reactive的数据可以直接访问,ref需要通过.value访问(模板中自动解包,不需要.value)。

  4. 重新赋值reactive重新赋值整个对象会丢失响应式,ref重新赋值.value或整个ref都能保持响应式。

  5. 解构reactive直接解构会丢失响应式,需要配合toRefs使用;ref解构后仍保持响应式。

使用建议:对象/表单数据用reactive,基本类型和需要整体替换的数据用ref

http://www.jsqmd.com/news/625682/

相关文章:

  • 清音刻墨惊艳案例:交响乐指挥解说视频中术语与乐段精准同步
  • 【奇点密档·RAG架构白皮书】:基于2026大会实测数据的向量库选型决策树(Milvus/Weaviate/Qdrant终极对比)
  • Redis持久化:从AOF到RDB,如何实现数据不丢失?烈
  • 直播食安爆雷不断!2026新规落地,维权终于有了硬保障
  • FLUX.1-dev实战教程:像素幻梦中自定义采样器(Sampler)切换与效果差异
  • 微软简化 Windows 预览体验计划,重塑测试生态
  • SpringBoot集成Milo搞定西门子PLC数据采集:一个KEPware服务端的Java实战
  • 别再乱裁CT了!用MONAI的CropForegroundd精准锁定病灶区域(附代码避坑)
  • Win+Docker+qwen.本地化养虾蹲
  • Windows环境下利用vcpkg高效部署CGAL的完整指南
  • 计算机毕业设计:Python大气污染物浓度预测与可视化系统 Django框架 Spark 线性回归 可视化 大数据 机器学习 深度学习(建议收藏)✅
  • AI Coding越来越强,我们还有必要学Processing吗? · 创意编程贝
  • 结对项目:花见小路 - fly
  • CSP-J模拟赛 - 枢纽
  • 终极Windows Defender完全控制指南:开源工具实现永久禁用
  • 【GUI-Agent】阶跃星辰 GUI-MCP 解读---()---HITL(Human In The Loop)厦
  • Ubuntu 虚拟机安装 OpenClaw 完整流程
  • ScanNetv2数据集下载与处理全攻略:从零开始搭建3D点云实验环境
  • NOI2026做题记录 四
  • AI建站工具怎么选?一份给零基础老板的选型标准与对比指南
  • 从“社恐老板”到行业IP:中科云创如何用AI数字人,让我的福州制造厂火了
  • Phi-3-mini-128k-instruct指令跟随能力深度评测:复杂任务分解与执行
  • 嘉兴压力型白发养黑理疗馆推荐?黑奥秘四大专利成分矩阵,精准应对白发问题 - 美业信息观察
  • 高光谱成像基础(十)基于 LMM 的端元提取悸
  • 前端构建优化策略
  • 华为HCIP云计算新版4.0题库
  • ReplaceItems.jsx:智能对象替换技术彻底革新Adobe Illustrator工作流程
  • Windows 11 调整 Copilot 推广策略,AI 功能何去何从?
  • bootstrap-datetimepicker技术集成指南:企业级日期时间选择器深度解析
  • GLM-. 全面支持与 Gemini CLI 集成:HagiCode 的多模型进化之路椎