携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 26 天,点击查看活动详情
start
- 上文学习了 vue3 中的
ref
函数; - 官方有这么一句话 "ref() 当值为对象类型时,会用
reactive()
自动转换它的.value
。" - 今天就来学习一下
reactive()
开始
1. 基础知识
解释:
返回一个对象的响应式代理。
基础使用:
<template>
<div>
reactive学习
{{ obj.count }}
<br />
<button @click="add">添加</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
const obj = reactive({ count: 0 })
function add() {
obj.count++
}
return {
obj,
add,
}
},
}
</script>
总结:
- reactive() 参数接受一个对象。返回一个响应式对象。
- 响应式的对象 : Proxy {count: 0}
2. 特殊的传参
上一个小节的演示代码是传入一个普通的对象。那么我们传入其他类型的数据会如何?
1. 基础类型数据:
<script>
import { reactive } from 'vue'
export default {
setup() {
const obj = reactive({ count: 0 })
console.log(obj)
let num = reactive(0)
console.log('num', num) // num 0
let str = reactive('tomato')
console.log('str', str) // str tomato
let bean = reactive(false)
console.log('bean', bean) // bean false
let un = reactive(undefined)
console.log('un', un) // un undefined
let nu = reactive(null)
console.log('nu', nu) // nu null
let sym = reactive(Symbol('hello'))
console.log('sym', sym) // sym Symbol(hello)
let bigNum = reactive(10n)
console.log('bigNum', bigNum) // bigNum 10n
/* 还会有这么一个警告 */
/* value cannot be made reactive */
},
}
</script>
2. 向 reactive() 传入 ref() 返回的对象
2.1 普通的传入 --- 会解包
<script>
import { ref, reactive } from 'vue'
export default {
setup() {
// 1. 获得一个 RefImpl 的实例对象
const count = ref(1) // { value : 1 }
// 2. 获得一个 Proxy 的实例对象
const obj = reactive({ count }) // { count:{ value : 1 } }
// 3. 比较两个值,居然不相等 ?
console.log(count.value === obj.count.value) // false
// 4. reactive() 将深层地解包任何 ref 属性,同时保持响应性。
console.log(count.value === obj.count) // true
// 5. 修改 ref 的返回值,也会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2
// 6.修改 reactive 的返回值,也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3
},
}
</script>
2.2 传入 响应式数组
或 map
中的ref()
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)
2.3 将一个 ref 赋值给为一个 reactive
属性,会被解包
const count = ref(1)
const obj = reactive({})
obj.count = count
console.log(obj.count) // 1
console.log(obj.count === count.value) // true
总结
reactive() 传入 ref() 的返回值:
- 对象中的 ref() 会解包;
- 数组和 map 结构中的 ref() ,不会解包;
- 对
reactive
属性赋值,会解包;
3. 其他注意事项:
-
响应式转换是“深层”的:它会影响到所有嵌套的属性。
<template> <div> <div> {{ obj1.a }} {{ obj1.b.c.d }} <button @click="add">增加</button> </div> </div> </template> <script> import { reactive } from 'vue' export default { setup() { var obj1 = reactive({ a: 1, b: { c: { d: 1 } } }) function add() { obj1.a++ obj1.b.c.d++ } return { obj1, add, } }, } </script>
-
reactive()
返回的是一个原始对象的 Proxy ,它和原始对象是不相等的let obj = { a: 1 } let obj1 = reactive(obj) console.log(obj === obj1) // false console.log(obj1 === reactive(obj)) // true
-
reactive()
API 有两条限制:-
仅对对象类型有效(对象、数组和
Map
、Set
这样的集合类型),而对string
、number
和boolean
这样的原始类型无效。 -
因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失:
const state = reactive({ count: 0 }) // n 是一个局部变量,同 state.count // 失去响应性连接 let n = state.count // 不影响原始的 state n++ // count 也和 state.count 失去了响应性连接 let { count } = state // 不会影响原始的 state count++
-
总结:
reactive()
参数支持 对象、数组和Map
、Set
类型;- 返回一个响应式的 Proxy 实例;
- 传入 ref() 会自动解包,(不包括 数组 map结构)
疑惑:
- Proxy 是什么?