reactive
根据传入的对象 ,创建返回一个深度响应式对象。响应式对象看起来和传入的对象一样,但是,响应式对象属性值改动,不管层级有多深,都会触发响应式。新增和删除属性也会触发响应式。
import { reactive } from 'vue'
type My {
name: string,
age: number
}
let person = reactive<My>({
name: '小张',
age: 23
})
// 使用reactive 修改值时不需要通过.value
person.age = 18
注意
reactive 不可以绑定普通数据类型
reactive 只支持引用类型 array object map set
ref 支持所有类型 如果用ref去绑定对象或者数组等复杂的数据类型,源码里面也是去调用reactive创建
reactive 不可直接赋值
reactive是一个proxy代理的对象, 不可直接赋值, 否则会破坏响应式对象**
import { reactive } from 'vue'
let list = reactive<nmumber[]>([])
const change = () => {
list = [1, 2, 3]
// 这样赋值页面是不会变化的,直接赋值会脱离响应式
}
解决方法:
- 数组使用
push+解构赋值
import { reactive } from 'vue'
let list = reactive<nmumber[]>([])
const change = () => {
const arr = [1, 2, 3]
// 使用push+解构赋值
list.push(..arr)
}
- 把数组改为对象属性进行赋值
import { reactive } from 'vue'
type State = {
list?:Array<number>
}
let state = reactive<State>({
list: []
})
const change = () => {
const arr = [1, 2, 3]
// 通过对象属性进行赋值
state.list = arr
}
shallowReactive
用来创建一个浅层响应式对象;这里没有深层级的转换:一个浅层响应式对象里只有根级别的属性是响应式的
import { shallowReactive } from 'vue'
const obj = {
a: 1,
first: {
b: 2
}
}
const state = shallowReactive(obj)
const change = () => {
state.a = 7 // 页面可以动态响应
state.first = { e: 12 } // 页面可以动态响应
state.first.b = 8 // 页面无法动态响应 但console.log打印出来的结果是改变后的
console.log(state);
}
reactive 源码解析
源码路径: /packages/reactivity/src/reactive.ts
// <T extends object> 通过泛型约束,只能传入引用类型的参数
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version.
if (isReadonly(target)) { // 如果是只读的就直接返回
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
)
}
createReactiveObject
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
// 如果传入的是普通类型就直接返回并返回一个警告
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// exception: calling readonly() on a reactive object
// 如果对象已经被proxy代理过了,也是直接返回
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
// target already has corresponding Proxy
// 通过缓存的WeakMap去查找,如果能从缓存中找到就直接返回,设置缓存的代码在下面
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// only specific value types can be observed.
// 如果在白名单中也直接返回,例如 通过markRaw添加__skip__跳过代理
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
// 上面所有的条件都没触发 才会通过proxy去代理
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy) // 设置缓存
return proxy
}
readonly
拷贝一份proxy对象,将其设置为只读
import { reactive ,readonly} from 'vue'
const person = reactive({count:1})
person.count++ // 可以正常运行
const copy = readonly(person)
copy.count++ // 页面报错 readonly只能读取,无法修改