ref
ref处理基本类型
import { ref } from 'vue'
const count = ref(0)
function changeCount(){
console.log(count)
//通过.value获取数据
count.value++
}
console.log结果:
ref()会返回一个RefImpl对象,将我们的数据放在了这个对象的value属性中,上图中可以看到value属性有get 和set方法,ref底层其实是通过Object.defineProperty()来实现响应式的
ref处理复杂数据类型
import { ref } from 'vue'
let refObj = ref({
count:1
})
function changeRefObjCount(){
refObj.value.count++
console.log(refObj)
}
console.log结果:
从图上可以看到ref()返回的还是一个RefImpl对象,数据依旧被放在了value属性上,value依旧有get和set方法,但是此时的value是一个Proxy对象,ref定义复杂类型响应式数据时,底层其实是通过Object.defineProperty和Proxy一起实现的
ref()实现的响应式是深度的
let refDeepObj = ref({
student:{
address:{
city:'chengdu'
}
}
})
function changeAddress(){
refDeepObj.value.student.address.city = 'xian'
console.log(refDeepObj)
}
<div>ref深度响应式:</div>
<div>{{refDeepObj.student.address.city}}</div>
<button @click="changeAddress">修改address</button>
修改前:
修改后:
在模板中使用ref定义的响应式数据
在模板中使用ref定义的响应式数据时,不需要使用.value去获取,因为在模板中自动帮我们解包了
// 基本类型
<div>{{count}}</div>
// 复杂类型
<div>{{refObj.count}}</div>
但是模板中自动解包有个前提条件:这个ref响应式数据必须是模板渲染上下文中的顶层属性
let x = ref(1)
let y = {z:ref(1)}
<div> x:{{x+1}}</div>
<div> y:{{y.z+1}}</div>
<div> y(.value):{{y.z.value+1}}</div>
最终页面呈现结果:
x作为顶层属性被自动解包,y.z这个ref响应式对象不是顶层属性,在模板中不会自动解包,需要使用.value去获取数据
但是但是但是,如果y.z作为插值语法中表达式的最终值又会自动解包了
<div>y.z作为文本插值最终值:{{y.z}}</div>
页面呈现效果:
这种情况其实是它自动帮你处理了,<div>y.z作为文本插值最终值:{{y.z}}</div>
就相当于<div>y.z作为文本插值最终值:{{y.z.value}}</div>
shallowRef
ref实现的响应式是深度的,那如果有一个数据,他层次比较深,但是他里面的属性是不会被修改,要修改只会被整体替换修改,如果使用ref来处理响应式就不是很合适了
shallowRef可以实现浅层响应式,对于普通类型来说,实现的效果和ref没有区别,对于复杂类型来说,它只会去响应第一层的修改
修改非第一层数据:
let shallowRefObj = shallowRef({
a:{
b:{
c:1
}
}
})
function changeC(){
shallowRefObj.value.a.b.c++
console.log(shallowRefObj.value.a.b.c)
}
数据发生了变化,但是页面没有响应变化
修改第一层数据:
let shallowRefObj = shallowRef({
a:{
b:{
c:1
}
}
})
function change(){
shallowRefObj.value=1
console.log(shallowRefObj.value)
}
修改前:
修改后:
数据发生变化,页面也响应了这个变化
shallowRef处理复杂数据数据类型,只有在修改.value的时候才会被监测到
reactive
import { reactive } from 'vue'
const state = reactive({ count: 0 })
reactive()返回的是一个Proxy对象,reactive底层是通过Proxy来实现响应式的
Usage in template:
<button @click="state.count++">
{{ state.count }}
</button>
代理一致性
- reactive返回的是原始对象的Proxy,与原始对象不相等
const originObj = {}
const originProxy = reactive(originObj)
console.log(originObj===originProxy) // false
- 对同一个原始对象调用reactive()会总是返回同样的代理对象
console.log(originProxy === reactive(originObj)) // true
- 对一个已经存在的代理对象调用reactive()会返回其本身
console.log(originProxy === reactive(originProxy)) //true
局限性
- 只能处理复杂类型数据
let numberReactive = reactive(0)
直接报错:
- 一个代理对象被整个替换为另一个代理对象不会被监测到
let state = reactive({ count: 0 })
function replaceState(){
state = reactive({count:1})
console.log(state.count) // 1
}
<div>{{state}}</div>
<button @click="replaceState"> 整个替换reactive代理对象</button>
修改前:
修改后:
打印出来的数据是修改以后的数据,对于reactive的代理对象整个替换没办法被监测到
3.解构后丢失响应式
let state = reactive({ count:1})
let {count} = state
<div>{{count}}</div>
<button @click="count++">修改reactive中解构出的count</button>
修改前&修改后:
4.代理对象属性作为实参传入,会失去反应式连接
let state = reactive({count:1})
function changeCount(count){
count++
console.log(state)
}
<div>{{state.count}}</div>
<button @click="changeCount(state.count)">代理对象属性作为实参传入进行修改</button>
修改前&后:
打印数据:
数据也没有发生变化,可以理解为传入的数据和代理对象没有关联
shallowReactive
修改对象非顶层数据
let shallowReactiveObj = shallowReactive({
a:{
b:{
c:1
}
}
})
function change(){
shallowReactiveObj.a.b.c++
console.log(shallowReactiveObj.a.b.c)
}
修改对象顶层数据
let shallowReactiveObj = shallowReactive({
count:0,
a:{
b:{
c:1
}
}
})
function change(){
shallowReactiveObj.count++
console.log(shallowReactiveObj.count)
}
ref作为reactive属性值
- ref作为reactive对象属性时,会自动展开,行为类似于普通属性
let a = ref(0)
let obj = reactive({
a,
})
function changeA(){
// 此处不用写成obj.a.value
obj.a++
console.log(obj.a) //1
}
changeA()
- 新的ref赋值给关联了ref的属性,会被替换,原来的ref与reactive对象失去关联
let a = ref(0)
let b = ref(0)
let obj = reactive({
a,
})
function changeA(){
obj.a=b
obj.a++
console.log(obj.a) // 1
console.log(b.value) // 1
console.log(a.value) // 0
}
- 只有当嵌套在一个深层响应式对象内时,才会自动解包,作为浅层响应式对象,属性被访问时不会被自动解包
let a = ref(0)
let b = ref(0)
let obj = reactive({
a,
})
let shallowObj = shallowReactive({
b
})
function changeA(){
obj.a++
console.log(obj.a) // 1
shallowObj.b.value++
console.log(shallowObj.b.value) // 1
//不会自动解包
shallowObj.b++
console.log(shallowObj.b) // NaN
}
ref出现在数组或集合中
ref作为属性值出现在数组和集合中,使用时不会被自动解包
let arr = reactive([ref(0)])
console.log(arr[0]) // RefImpl对象
let map = reactive(new Map([['count',ref(0)]]))
console.log(map.get('count'))