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
会自动解包。