一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
上一篇章中我们简单的介绍了createApp函数,ref相关的一些API,以及v-model在父子组件传参上的写法,本篇章打算总结一下reactive相关的API。
往期vite项目搭建过程地址
reactive
- 返回对象的响应式副本(对象、数组...)
- 如果我们使用ref绑定复杂数据类型(例如
const data = ref<string[]>([])),在Vue3的底层其实也是使用reactive来定义的。
按照惯例,我们简单看看reactive的类型定义
export declare function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
上面的注释对reactive进行了一下简单描述,大体意思如下:reactive会创建一个原始对象的副本。响应式的转化是深层次的,他会影响所有嵌套属性,在基于ES2015 Proxy的实现中,返回的 proxy 是不等于原始对象的。建议只使用响应式 proxy,避免依赖原始对象。响应式对象也会自动打开其中包含的参照,因此不需要使用.value当访问和改变它们的值(当将 ref 分配给 reactive property 时,ref 将被自动解包)。
从它的定义上可以看出它是不可以绑定普通的数据类型
数组的异步赋值问题
碰到过这样一个问题,需求是在下拉框中需要使用后台给的数据,当我们在进入页面后对使用reactive定义的数组进行赋值,发现其失去了响应式(页面上的效果是下拉框中没有值了)。
这样直接赋值页面是不会产生变化的,因为会脱离响应式
let optionsData = reactive<string[]>([]);
onMounted(() => {
optionsData = ['v1', 'v2', 'v3'];
})
当然如果是一个简单的数组,也可以使用ref来定义,这样在使用时通过.value来赋值也是可以的。
方法一、使用push
let optionsData = reactive<string[]>([]);
onMounted(() => {
const data = ['v1', 'v2', 'v3'];
optionsData.push(...data);
});
方法二、在数组外面包裹一层对象
type Data = {
optionsData: Array<string>
}
let data = reactive<Data>({
list: []
});
onMounted(() => {
data.list = ['v1', 'v2', 'v3'];
});
推荐使用方法二
readonly
接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 property 也是只读的。
import { reactive, readonly } from 'vue';
const data = reactive({
count: 1,
});
const copyData = readonly(data);
data.count++;
copyData.count++;// 变更副本将失败并导致警告-报错
如果任何 property 使用了 ref,当它通过代理访问时,则被自动解包
const raw = {
count: ref(123)
}
const copy = readonly(raw)
console.log(raw.count.value) // 123
console.log(copy.count) // 123
shallowReactive
创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
// 改变 state 本身的性质是响应式的
state.foo++
// ...但是不转换嵌套对象
isReactive(state.nested) // false
state.nested.bar++ // 非响应式
其他的API
isProxy: 检查对象是否是由reactive或readonly创建的 proxyisReactive: 检查对象是否是由reactive创建的响应式代理
const data = reactive({
count: 1
})
console.log(isReactive(data)) // true
如果该代理是由 readonly 创建的,但是包裹了由 reactive 创建的另一个代理,它也会返回 true
const data = reactive({
count: 1
})
// 从普通对象创建的只读proxy
const plain = readonly({
name: '张三'
});
console.log(isReactive(plain)) // false
// 从响应式 proxy 创建的只读 proxy
const dataCopy = readonly(data)
console.log(isReactive(dataCopy)) // -> true
isReadonly:检查对象是否是由readonly创建的只读代理toRaw: 返回reactive或readonly代理的原始对象shallowReactive: 创建一个响应式代理,它只跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)-(类似于shallowRef只跟踪自身.value的变化)。shallowReadonly: 创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)
const data = shallowReadonly({
foo: 1,
nested: {
bar: 2
}
})
// 改变 data 本身的 property 将警告,报错
data.foo++
// ...但适用于嵌套对象
isReadonly(data.nested) // false -> 不是由readonly创建的只读代理
data.nested.bar++ // 可以使用