持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情
reactive(obj|arr)
reactive函数接收一个对象或者数组作为参数,如果你使用一个原始类型的值作为其参数的话,则会在控制台得到一个警告 value cannot be made reactive: ${String(target)}。
在源码中可以知道,调用reactive函数的时候,会先使用isReadonly函数判断reactive的参数是只读代理对象还是响应式代理对象,如果不是只读代理的话,就会调用createReactiveObject去创建一个响应式的对象。
而createReactiveObject函数,会先调用isObject函数判断传入的target参数是否为原始类型,如果是原始类型,则直接返回该参数,在开发模式下(即__DEV__特性为真),还会在控制台打印出一个警告。 接着判断target参数是否已经是响应式对象了,如果是的话,也是直接返回该参数。经过几重判断之后,最后才使用Proxy为target参数创建一个代理对象,然后返回该代理对象。
reactive的使用方式如下
// 对象
let obj = reactive({
name: 'mac'
})
obj.name = 'xxx' // 直接修改,不需要像ref那样还要经过一个.value属性
// 数组
let arr = reactive([])
reactive的使用比ref要简洁一些,但是有一个点要注意点就是,不能直接给reactive包裹的值赋值,比如说上面定义的arr变量,在vue的时候,我们请求一个接口,返回一个数组,通常都是直接将这个数组赋值给data中的某个变量的,但是在这里则不可以这么做了,因为这么做会破坏它的响应式。
// 模拟接口
setTimeout(() => {
let res = [1, 2, 3] // 假设是响应数据
// arr = res // 这样是错误的,会导致arr失去响应式,在页面无法更新
// 我们更多的是使用下面这种方式
arr.push(...res)
}, 1000)
除了上面这个使用扩展运算符的方法之外,我们还可以使用reactive包裹一个对象,对象中的某个属性是数组,然后我们直接将请求结果赋值给这个对象的这数组属性,像下面这样:
let arrObj = reactive({
list: []
})
setTimeout(() => {
let res = [1, 2, 3]
arrObj.list = res
}, 1000)
readonly
拷贝一份proxy对象,并且将其设置为只读。 只读的代理对象将无法修改其属性。
let obj = reactive({
name: 'mac'
})
let copy = readonly(obj)
copy.name = 'xxx' // 报错
shallowReactive
只能对浅层的数据,如果是深层的数据只会改变其值,而不会改变视图。常用于多层次的对象。
const man = shallowReactive({
name: 'mac',
subject: {
Chinese: {
score: 100
}
}
})
像上面这个man对象,当你修改它的第一层属性name和subject的值的时候,视图上也会更新,但是,如果你去修改subject中的属性的值的时候,视图上则不会更新。
还有一个地方是需要注意的,就是在DOM挂载前,修改shallowReactive深层次的属性是可以的,会在视图上显示出来,挂载后再去修改shallowReactive深层次的属性则只有值改而试图不变,像下面这样:
// 这是在setup中
const change1 = ()=>{
man.name = 'xxx'
}
const change2 = ()=>{
man.subject.Chinese.score = 2000
}
// 这是在setup中调用,相当于是在DOM挂载前改变了shallowReactive的值,因此会在视图上也显示出来。
change1()
change2()
而如果我们在DOM挂载后才去改变它们的属性值,则shallowReactive不会在视图上更新,比如说我把change2绑定到一个按钮上,点击按钮则视图不会更新。