前端小知识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:当管理具有多个相关属性的复杂对象状态时
  • 保持一致性:在同一项目中建立统一的使用规范
相关推荐
消失的旧时光-19433 小时前
Kotlinx.serialization 对多态对象(sealed class )支持更好用
java·服务器·前端
少卿3 小时前
React Compiler 完全指南:自动化性能优化的未来
前端·javascript
广州华水科技3 小时前
水库变形监测推荐:2025年单北斗GNSS变形监测系统TOP5,助力基础设施安全
前端
广州华水科技3 小时前
北斗GNSS变形监测一体机在基础设施安全中的应用与优势
前端
七淮3 小时前
umi4暗黑模式设置
前端
8***B3 小时前
前端路由权限控制,动态路由生成
前端
军军3604 小时前
从图片到点阵:用JavaScript重现复古数码点阵艺术图
前端·javascript
znhy@1234 小时前
Vue基础知识(一)
前端·javascript·vue.js
terminal0074 小时前
浅谈useRef的使用和渲染机制
前端·react.js·面试
我的小月月4 小时前
🔥 手把手教你实现前端邮件预览功能
前端·vue.js