前端小知识002:ref 与 reactive 详解

Vue 3 的响应式系统是其核心亮点之一,它让数据变化自动触发视图更新。refreactive 是 Composition API 中最常用的响应式工具,但它们在用法、适用性和底层机制上存在明显差异。


一、基础概念:ref 和 reactive 是什么?

Vue 的响应式系统基于 Proxy 和 Reflect API 实现,能"监听"数据的读写操作,并在变化时通知依赖(如模板或计算属性)。

1.1 ref:响应式引用,适用于任何类型

ref 是一个函数,它将任意 JavaScript 值(基本类型或对象)包装成一个响应式引用(Ref)。这个引用有一个 .value 属性,用于访问或修改内部值。

为什么需要 ref?

Vue 需要一个"容器"来追踪值的变化。对于基本类型(如数字、字符串),它们不是对象,无法直接用 Proxy 代理,所以 ref 用一个对象"包裹"它们。

简单示例:

javascript 复制代码
import { ref } from 'vue'

const count = ref(0)  // 创建响应式数字
const user = ref({ name: 'Alice' })  // 创建响应式对象
const items = ref([1, 2, 3])  // 创建响应式数组

// 在模板中使用:{{ count }} 或 {{ user.name }}
// 变化时:count.value++  // 视图自动更新

import { ref } from 'vue'

const count = ref(0)
const object = ref({ value: 1 })
const array = ref([1, 2, 3])

reactive 专用于创建响应式对象,仅支持对象类型:

javascript 复制代码
import { reactive } from 'vue'

const state = reactive({ 
  count: 0,
  nested: { value: 1 }
})
const list = reactive([1, 2, 3])

二、核心差异分析

2.1 数据类型支持

ref 支持所有 JavaScript 数据类型:

  • 基本类型:string、number、boolean、null、undefined、symbol

  • 引用类型:Object、Array、Function、Map、Set

reactive 仅支持引用类型:

  • 有效:Object、Array、Map、Set

  • 无效:所有基本类型

2.2 访问方式差异

ref 需要通过 .value 属性访问:

javascript 复制代码
const count = ref(0)
console.log(count.value) // 读取
count.value = 1         // 写入

reactive 直接访问属性:

javascript 复制代码
const state = reactive({ count: 0 })
console.log(state.count) // 读取
state.count = 1         // 写入

2.3 实现机制对比

ref 基于对象的属性访问器:

javascript 复制代码
class RefImpl {
  constructor(value) {
    this._value = value
  }
  
  get value() {
    track(this, 'value')
    return this._value
  }
  
  set value(newVal) {
    this._value = newVal
    trigger(this, 'value')
  }
}

reactive 基于 Proxy 代理:

javascript 复制代码
function reactive(target) {
  return new Proxy(target, {
    get(obj, key) {
      track(obj, key)
      return obj[key]
    },
    set(obj, key, value) {
      obj[key] = value
      trigger(obj, key)
      return true
    }
  })
}

三、reactive的缺点

3.1 响应式丢失问题

javascript 复制代码
// 错误示例:响应式丢失
const state = reactive({ count: 0, name: '' })
const { count, name } = state

// 正确方案:使用 toRefs
const state = reactive({ count: 0, name: '' })
const { count, name } = toRefs(state)

3.2 重新赋值问题

javascript 复制代码
// 错误:失去响应式
let state = reactive({ count: 0 })
state = reactive({ count: 1 })

// 正确:修改属性
const state = reactive({ count: 0 })
state.count = 1

// 或使用 ref
const state = ref({ count: 0 })
state.value = { count: 1 }

四、适合场景

4.1 ref 适用场景

  • 基本类型数据(字符串、数字、布尔值等)
  • 需要在响应式系统外管理的引用(如 DOM 元素、定时器)
  • 组合式函数的返回值
  • 需要重新赋值的响应式变量
  • 模板引用(template refs)

4.2 reactive 适用场景

  • 相关联的复杂对象状态(如表单数据、配置对象)
  • 需要保持引用一致性的嵌套数据结构
  • 多个相关属性的集合(如分页参数、用户信息)
  • 需要直接访问属性而不需要 .value 的场合

4.3 选择原则

  • 优先使用 ref:当处理独立值、基本类型或需要明确类型提示时
  • 选择 reactive:当管理具有多个相关属性的复杂对象状态时
  • 保持一致性:在同一项目中建立统一的使用规范
相关推荐
layman05281 小时前
webpack5 css-loader:从基础到原理
前端·css·webpack
半桔1 小时前
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典
前端·css·html
AI老李1 小时前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·postcss
_OP_CHEN1 小时前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化
啊哈一半醒1 小时前
CSS 主流布局
前端·css·css布局·标准流 浮动 定位·flex grid 响应式布局
PHP武器库2 小时前
ULUI:不止于按钮和菜单,一个专注于“业务组件”的纯 CSS 框架
前端·css
电商API_180079052472 小时前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫
晓晓莺歌2 小时前
vue3某一个路由切换,导致所有路由页面均变成空白页
前端·vue.js
Up九五小庞2 小时前
开源埋点分析平台 ClkLog 本地部署 + Web JS 埋点测试实战--九五小庞
前端·javascript·开源
qq_177767373 小时前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos