前端小知识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:当管理具有多个相关属性的复杂对象状态时
  • 保持一致性:在同一项目中建立统一的使用规范
相关推荐
原则猫1 小时前
HOOKS 背后机制
前端
码语智行1 小时前
首页导航跳转功能深度解析-系统内和系统外
前端
阿猫的故乡2 小时前
Vue过渡动画从入门到装X:淡入淡出、滑动、列表动画、第三方库全搞定
前端·javascript·vue.js
IManiy2 小时前
总结之Vibe Coding前端骨架
前端
JS菌2 小时前
AI Agent 沙箱双层防护体系:从权限过滤到内核隔离的完整实现
前端·人工智能·后端
Aphasia3112 小时前
从输入URL到页面展示全流程
前端·面试
我叫黑大帅3 小时前
前端如何竖屏固定视口背景
前端·javascript·面试
abcy0712133 小时前
python pandas csv异步后台清洗前端优先返回成功信息
前端·python·pandas
IT_陈寒3 小时前
Vite这个坑我帮你踩了,动态导入居然这样才生效
前端·人工智能·后端
swipe3 小时前
Mem0 x Agent 实战系列:分层记忆 + 三路召回,搭建真正可用的长期记忆层
前端·javascript·面试