Vue 3 中响应式的两大核心 API:ref() 和 reactive() 的原理与用法。
一、ref()
1. 用法
ref() 用于为基本类型(如字符串、数字、布尔值)或对象/数组创建一个响应式的数据引用。
- 它返回一个带有
.value 属性的响应式对象。
示例
1 2 3 4 5 6 7
| import { ref } from 'vue'
const count = ref(0) const user = ref({ name: 'Tom' })
count.value++ user.value.name = 'Jerry'
|
2. 原理
ref() 内部通过 Object.defineProperty 或 Proxy 实现,将传入的值包裹在一个对象的 value 属性中。
- 当
.value 发生变化时,依赖于它的组件会自动重新渲染。
3. 适用场景
- 适合基本类型数据(如数字、字符串、布尔值)。
- 也可用于对象/数组,但访问和赋值都要通过
.value。
二、reactive()
1. 用法
reactive() 用于将一个对象或数组变成响应式对象。
- 返回的就是原对象的 Proxy 代理,不需要
.value。
示例
1 2 3 4 5 6 7 8 9
| import { reactive } from 'vue'
const state = reactive({ count: 0, user: { name: 'Tom' } })
state.count++ state.user.name = 'Jerry'
|
2. 原理
reactive() 内部通过 ES6 的 Proxy 拦截对象的 get/set 操作,实现依赖收集和响应式更新。
- 只有对象和数组才能用
reactive(),基本类型不能直接用。
3. 适用场景
- 适合复杂的对象/数组,如组件的 state、表单数据等。
- 访问和赋值都像普通对象一样,无需
.value。
三、ref() 和 reactive() 的区别与联系
| 适用类型 |
基本类型/对象/数组 |
对象/数组 |
| 访问方式 |
通过 .value |
直接访问属性 |
| 内部实现 |
对象包装 + Proxy/defineProperty |
Proxy |
| 响应式深度 |
浅层响应式(对象时递归) |
深层响应式 |
| 典型场景 |
单个变量、基本类型 |
复杂对象、表单、state |
例子
1 2 3 4 5
| const a = ref(1) a.value = 2
const b = reactive({ x: 1 }) b.x = 2
|
ref 对象的自动解包(在模板中)
在 <template> 里,ref 的 .value 会被自动解包,可以直接用 {{ count }} 而不是 {{ count.value }}。
四、进阶:ref 和 reactive 混用
reactive 里嵌套 ref,属性不会自动解包,需手动 .value。
- 推荐:对象用 reactive,基本类型用 ref。
示例
1 2 3 4
| const state = reactive({ count: ref(0) }) state.count.value++
|
五、总结
- 基本类型用
ref(),对象/数组用 reactive()。
ref 适合单一变量,reactive 适合复杂结构。
- 访问
ref 需 .value,reactive 直接访问。
- 在
<template> 中,ref 会自动解包。