基本用法
- 返回对象的响应式副本,只能代理对象,不能代理普通值
const obj = reactive({count: 0, name: 'hyh'})
const count = reactive(1)
// value cannot be made reactive: 1
- 响应式转换是“深层”的——它影响所有嵌套
property
const obj = reactive({count: 0, name: 'hyh', info: { age: 25 }})
console.log(obj.count) // 0
console.log(obj.info.age) // 25
reactive
将解包所有深层的refs
,同时维持ref
的响应性。
const count = ref(1)
const obj = reactive({ count })
// ref 会被解包
console.log(obj.count === count.value) // true
// 它会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2
// 它也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3
- 当将
ref
分配给reactive
property
时,ref
将被自动解包。
const count = ref(1)
const obj = reactive({})
obj.count = count
console.log(obj.count) // 1
console.log(obj.count === count.value) // true
实现原理
reactive
是基于 Proxy
实现的响应式。
const ReactiveFlags = {
SKIP = '__v_skip',
IS_REACTIVE = '__v_isReactive',
IS_READONLY = '__v_isReadonly',
RAW = '__v_raw'
}
// 用于缓存代理过的对象
const proxyMap = new WeakMap();
function createGetter(isReadonly = false, shallow = false){
return function get(target, key, receiver){
// 判断代理对象是否为数组
const targetIsArray = isArray(target);
if(targetIsArray && hasOwn(arrayInstrumentations, key)){
// 如果是特殊方法,没有进行依赖收集, 而是重写了一些方法
return Reflect.get(arrayInstrumentations, key, receiver)
}
// 获取到目标属性的值
const res = Reflect.get(target, key, receiver);
if(!isReadonly){
// 如果不是只读的属性, 当获取属性值的时候进行依赖收集
track(target, 'get', key)
}
// 如果只是浅层的 shallowReactive() shallReadonly()
if (shallow) {
return res;
}
if(isRef(res)){
// 判断是否需要解包
// ref unwrapping - does not apply for Array + integer key.
const shouldUnwarp = !targetIsArray || !isIntegerKey(key)
return shouldUnwarp ? res.value : res;
}
// 这里只有在用户取值的时候才会去对嵌套的对象进行响应式处理,相当于懒处理
if(isObject(res)){
return isReadonly ? readonly(res) : reactive(res)
}
return res
}
}
function createSetter(shallow = false){
return function set(target, key, value, receiver){
const oldValue = target[key]
const hadKey = hasOwn(target, key)
const res = Reflect.set(target, key, value, receiver);
// 触发effect更新
if(!hadKey){
trigger(target, 'add', key, value)
}else{
trigger(target, 'set', key, value, oldValue)
}
}
}
function mutableHandler(){
get: createGetter(),
set: cerateSetter(),
}
function reactive(target){
// 针对特殊场景 reactive(readonly(obj))-> 直接返回readonly即可
if(target && target[ReactiveFlags.IS_READONLY]){
return target
}
return createReactiveObject(target, false, mutaleHandler)
}
function createReactiveObject(target, isReadonly, baseHandler){
if(!isObject(target)){
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// target already has corresponding Proxy
const existingProxy = proxyMap.get(target) // 看目标是否被代理过
if (existingProxy) { // 如果代理过,直接返回代理过的对象
return existingProxy
}
const proxy = new Proxy( // 创建一个proxy对象
target,// 调用对应的handler进行代理
targetType: baseHandlers
)
proxyMap.set(target, proxy) // 存到缓存中
return proxy
}
以上代码只是Vue3的部分源码,简单的实现了reactive的响应式原理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南