网站首页 > 精选文章 正文
reactive()
还有另一种声明响应式状态的方式,即使用 reactive() API。与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性:
- 「点击按钮+1」
<script lang="ts" setup>
import { reactive } from 'vue'
const state = reactive({ count: 0 })
</script>
<template>
<div class="container">
<button @click="state.count++">
点击次数加+1 : {{ state.count }}
</button>
</div>
</template>
<style lang="scss" scoped>
.container {}
</style>
- 「示例效果」
响应式对象是 JavaScript 代理,其行为就和普通对象一样。不同的是,Vue 能够拦截对响应式对象所有属性的访问和修改,以便进行依赖追踪和触发更新。
reactive() 将深层地转换对象:当访问嵌套对象时,它们也会被 reactive() 包装。当 ref 的值是一个对象时,ref() 也会在内部调用它。与浅层 ref 类似,这里也有一个 shallowReactive() API 可以选择退出深层响应性。
- reactive() 返回的是一个原始对象的 Proxy,它和原始对象是不相等的
const raw = {}
const proxy = reactive(raw)
// 代理对象和原始对象不是全等的
console.log(proxy === raw) // false
只有代理对象是响应式的,更改原始对象不会触发更新。
因此,使用 Vue 的响应式系统的最佳实践是 「仅使用你声明对象的代理版本」。
- 为保证访问代理的一致性,对同一个原始对象调用 reactive() 会总是返回同样的代理对象,而对一个已存在的代理对象调用 reactive() 会返回其本身:
// 在同一个对象上调用 reactive() 会返回相同的代理
console.log(reactive(raw) === proxy) // true
// 在一个代理上调用 reactive() 会返回它自己
console.log(reactive(proxy) === proxy) // true
这个规则对嵌套对象也适用。依靠深层响应性,响应式对象内的嵌套对象依然是代理:
const proxy = reactive({})
const raw = {}
proxy.nested = raw
console.log(proxy.nested === raw) // false
reactive() 的局限性
- 有限的值类型:它只能用于对象类型 (对象、数组和如 Map、Set 这样的集合类型)。它不能持有如 string、number 或 boolean 这样的原始类型。
- 不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:
let state = reactive({ count: 0 })
// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 })
- 对解构操作不友好:当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接:
const state = reactive({ count: 0 })
// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++
// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count)
由于这些限制,我们建议使用 ref() 作为声明响应式状态的主要 API。
额外的 ref 解包细节
- 作为 reactive 对象的属性 一个 ref 会在作为响应式对象的属性被访问或修改时自动解包。换句话说,它的行为就像一个普通的属性:
const count = ref(0)
const state = reactive({
count
})
console.log(state.count) // 0
state.count = 1
console.log(count.value) // 1
- 如果将一个新的 ref 赋值给一个关联了已有 ref 的属性,那么它会替换掉旧的 ref:
const otherCount = ref(2)
state.count = otherCount
console.log(state.count) // 2
// 原始 ref 现在已经和 state.count 失去联系
console.log(count.value) // 1
只有当嵌套在一个深层响应式对象内时,才会发生 ref 解包。当其作为浅层响应式对象的属性被访问时不会解包。
数组和集合的注意事项
与 reactive 对象不同的是,当 ref 作为响应式数组或原生集合类型(如 Map) 中的元素被访问时,它不会被解包:
const books = reactive([ref('Vue 3 Guide')])
// 这里需要 .value
console.log(books[0].value)
const map = reactive(new Map([['count', ref(0)]]))
// 这里需要 .value 访问
console.log(map.get('count').value)//输出0
new Map([['count', ref(0)]] 这个理解起来就是
访问 key为count的对应value值
也就是一组键值对的结构,具有极快的查找速度。
ref自动解包就是无需加上.value访问,比如在模版中使用会自动解包{{msg}}
不会自动解包 就是需要再后面加上一个.value才能访问到值
Map是ES6规范引入新的数据类型。
猜你喜欢
- 2025-07-19 为什么react需要fiber架构,而vue却不需要?
- 2025-07-19 Vue 中的 Props 与 Data 细微差别,你知道吗?
- 2025-07-19 如何使用 Chrome DevTools(及 Vue Devtools)调试 Vue.js 应用
- 2025-07-19 VUE3 你不知道的按钮与菜单权限(vue按钮权限管理)
- 2025-07-19 什么是状态管理工具?(vuex)(状态管理具有哪两种方式)
- 2025-07-19 Vue3 开发总踩坑?这 10 个技巧让你少走半年弯路!
- 2025-07-19 Vue3 实战指南:15 个高效组件开发技巧解析
- 2025-07-19 Vue3 终于可以共享自己的屏幕给别人看了!
- 2025-07-19 vue3中到底使用Ref还是Reactive,我和同事吵起来了
- 2025-07-19 Vuex中 getters,...mapGetters使用
- 最近发表
-
- 为什么react需要fiber架构,而vue却不需要?
- Vue 中的 Props 与 Data 细微差别,你知道吗?
- 如何使用 Chrome DevTools(及 Vue Devtools)调试 Vue.js 应用
- VUE3 你不知道的按钮与菜单权限(vue按钮权限管理)
- vue3-响应式基础之reactive(vue3.0响应式原理)
- 什么是状态管理工具?(vuex)(状态管理具有哪两种方式)
- Vue3 开发总踩坑?这 10 个技巧让你少走半年弯路!
- Vue3 实战指南:15 个高效组件开发技巧解析
- Vue3 终于可以共享自己的屏幕给别人看了!
- vue3中到底使用Ref还是Reactive,我和同事吵起来了
- 标签列表
-
- 向日葵无法连接服务器 (32)
- git.exe (33)
- vscode更新 (34)
- dev c (33)
- git ignore命令 (32)
- gitlab提交代码步骤 (37)
- java update (36)
- vue debug (34)
- vue blur (32)
- vscode导入vue项目 (33)
- vue chart (32)
- vue cms (32)
- 大雅数据库 (34)
- 技术迭代 (37)
- 同一局域网 (33)
- github拒绝连接 (33)
- vscode php插件 (32)
- vue注释快捷键 (32)
- linux ssr (33)
- 微端服务器 (35)
- 导航猫 (32)
- 获取当前时间年月日 (33)
- stp软件 (33)
- http下载文件 (33)
- linux bt下载 (33)