网易首页 > 网易号 > 正文 申请入驻

web前端培训vue3响应式reactive源码分析

0
分享至

1. 先看一段基本使用

const { reactive, effect } = Vue

const target = {

name: 'lixx',

age: 27

const state = reactive(target)

const state1 = reactive(target)

const state2 = reactive(state1)

console.log(state === state1, state1 === state2) // true true

effect(() => {

document.getElementById('app').innerHTML = `我的名字是:${state.name}, 我${state.age}岁了`

setTimeout(() => {

state.age = 28

}, 4000)

  • 模块reactive是将对象变换为响应式
  • 模块effect可以理解为依赖追踪,就是函数内执行依赖发生变化,会自动执行函数,初期的时候会执行一次
  • 上述代码中state === state1, state1 === state2是为了引出reactive的缓存技巧

2. 实现一个简单的

手写内容包括:代理,缓存,懒代理

// 源码实现部分 -----------------------------------------------------------

// 进行reactive缓存

const reactiveMap = new WeakMap()

const isObject = (target) => target && typeof target === 'object'

const ReactiveFlags = {

IS_REACTIVE: '__v_isReactive'

const reactiveImpl = (target) => {

if (!isObject(target)) {

console.warn(`${target} need is object`)

return

// 如果传递的是源对象,源对象被代理过后,直接返回代理后的对象

// 这个缓存是 当target是代理前对象时

const existingProxy = reactiveMap.get(target)

if (existingProxy) return existingProxy

// 这个缓存时 当target是代理后对象时

if (target && target[ReactiveFlags.IS_REACTIVE]) return target

const proxy = new Proxy(target, {

get: (target, key, receiver) => {

if (key === ReactiveFlags.IS_REACTIVE) return true

const res = Reflect.get(target, key, receiver)

// 如果是对象,继续代理,然后返回

return isObject(res) ? reactive(res) : res

},

set: (target, key, value, receiver) => {

Reflect.set(target, key, value, receiver)

reactiveMap.set(target, proxy)

return proxy

const Vue = { reactive: reactiveImpl }

// 使用部分 -------------------------------------------------------------------

const { reactive } = Vue

const target = {

name: 'lixx',

age: 27

const state = reactive(target)

const state1 = reactive(target)

const state2 = reactive(state1)

console.log(state === state1, state1 === state2) // true true

document.getElementById('app').innerHTML = `我的名字是:${state.name}, 我${state.age}岁了`

  • 上述是reactive的核心部分,但是有几个点需要注意:
  • 如果传递给函数reactive的参数是源对象怎么办???
  • 如果传递给函数reactive的参数是代理后的对象怎么办???
  • 如果代理的对象是深层嵌套怎么办???
  • 根据上述的问题,通过我们手写实现来一一解答:
  • Vue中使用了懒代理的模式来解决嵌套的问题。【关注尚硅谷,轻松学IT】Vue3跟Vue2的区别之一就是:Vue2遇到迭代对象是递归重写的。但是Vue3是懒代理的
  • 通过代码return isObject(res) ? reactive(res) : res 来实现。
  • 这里有个疑问:如果让我们自己来判断对象是否已经代理过,我们应该怎么判断呢?
  • 通过target && target[ReactiveFlags.IS_REACTIVE] 来判断是否代理过。执行此代码时,如果target是代理后对象,那么一定会触发proxy.get函数的,我们就可以通过代码if (key === ReactiveFlags.IS_REACTIVE) return true来告诉用户变量被代理过
  • 直观的的办法:给proxy添加一个变量,判断变量是否存在。这种办法是可行的,但是如果我们不想让用户知道有这个变量怎么办呢,还有别的办法,那接下来看下Vue是如何做的
  • 如果传递的对象是代理前的对象,在源码中会调用proxy来进行代理
  • 将代理后的数据存放到reactiveMap.set(target, proxy) 中
  • 如果下次重复代理的时候,直接返回。可以通过上述代码state === state1 // true来体现出来
  • 问题1:如果传递给函数reactive的参数是源对象怎么办???
  • 问题2:如果传递给函数reactive的参数是代理后的对象怎么办???
  • 问题3:如果代理的对象是深层嵌套怎么办???

3. 源码细节扫描

3.1reactive只能传递对象

// 传递的属性 必须是对象

if (!isObject(target)) {

if (__DEV__) {

console.warn(`value cannot be made reactive: ${String(target)}`)

return target

3.2 如果被代理过了直接返回

// 此时传递对象是代理后对象www.atguigu.com

// 如果被代理过直接返回 主要是【target[ReactiveFlags.IS_REACTIVE]】起了作用

if (

target[ReactiveFlags.RAW] &&

!(isReadonly && target[ReactiveFlags.IS_REACTIVE])

return target

// 重复代理,多次传递同一个对象进行代理

// 判断缓存中是否有值 进行返回

const existingProxy = proxyMap.get(target)

if (existingProxy) {

return existingProxy

3.3 如果传递的target是数组单独处理

// 判断是否是数组

const targetIsArray = isArray(target)

if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {

return Reflect.get(arrayInstrumentations, key, receiver)

3.4 如果不是只读,收集依赖

// 如果不是只读, 触发依赖收集

if (!isReadonly) {

track(target, TrackOpTypes.GET, key)

3.5 如果是浅代理,代理一层后直接返回

// 如果是浅代理 直接返回

if (shallow) {

return res

3.6 如果是ref,直接调用.value进行返回

// 如果代理的ref 直接使用【.value】进行返回

if (isRef(res)) {

// ref unwrapping - skip unwrap for Array + integer key.

return targetIsArray && isIntegerKey(key) ? res : res.value

3.7 如果是深层对象,进行懒代理

// 如果返回的值对象 进行懒代理 然后返回

if (isObject(res)) {

return isReadonly ? readonly(res) : reactive(res)

文章转载来源于前端干货寺院

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
中午,医生来把尿管拔了,我给妈妈清洗了一下。她什么也没问...

中午,医生来把尿管拔了,我给妈妈清洗了一下。她什么也没问...

小刀99
2024-05-11 09:45:09
外贸订单去哪了?低中高端市场全面崩溃,未来只能依赖国内消费?

外贸订单去哪了?低中高端市场全面崩溃,未来只能依赖国内消费?

庞明说财经
2024-05-11 11:15:26
一集入坑!尺度大到头皮发麻!

一集入坑!尺度大到头皮发麻!

天天美剧吧
2024-06-20 11:48:06
国产002航母锈迹斑斑,还没服役就破烂不堪?专家给出解释

国产002航母锈迹斑斑,还没服役就破烂不堪?专家给出解释

零点历史说
2024-06-07 11:47:30
帮助乌克兰人的代价

帮助乌克兰人的代价

非虚构故事
2024-05-17 22:34:41
亲绿民调称韩国瑜倒数第三,媒体人质疑韩为何会在“阁员”民调里,怎么没陈菊

亲绿民调称韩国瑜倒数第三,媒体人质疑韩为何会在“阁员”民调里,怎么没陈菊

海峡导报社
2024-06-21 09:22:15
御姐风!太高级!要不起的感觉

御姐风!太高级!要不起的感觉

梧州生活宝
2024-05-22 23:14:03
六月这些星座财星高照,喜事频传福气连连

六月这些星座财星高照,喜事频传福气连连

观星星座
2024-06-21 08:30:01
瑞典女网红:和C罗吃晚餐 他不喝酒只要了杯水 他想要保持6块腹肌

瑞典女网红:和C罗吃晚餐 他不喝酒只要了杯水 他想要保持6块腹肌

罗克
2024-06-20 10:05:39
惊!悄无声息的055“大连舰”现身菲律宾沿岸,疑似进入12海里

惊!悄无声息的055“大连舰”现身菲律宾沿岸,疑似进入12海里

武器纵论
2024-06-20 22:35:53
Manner咖啡店员情绪失控向顾客泼咖啡粉,品牌方回应了

Manner咖啡店员情绪失控向顾客泼咖啡粉,品牌方回应了

南方都市报
2024-06-20 16:48:07
突发改口!495天以来,房地产第一次

突发改口!495天以来,房地产第一次

说财猫
2024-06-20 22:35:36
周杰深夜发文评《歌手》,直言节目弊端,引发热议

周杰深夜发文评《歌手》,直言节目弊端,引发热议

明星爆料客
2024-06-18 13:46:55
魔术师:任命雷迪克为主教练只是第一步 佩林卡必须改善球队阵容

魔术师:任命雷迪克为主教练只是第一步 佩林卡必须改善球队阵容

直播吧
2024-06-21 08:18:13
火锅店卷起“新型菜单”!背后是贴脸价格战?

火锅店卷起“新型菜单”!背后是贴脸价格战?

火锅餐见
2024-06-20 09:29:36
50岁富婆夜间约会帅哥,凌晨对方哀求“歇一会吧”,竟还心怀叵胎

50岁富婆夜间约会帅哥,凌晨对方哀求“歇一会吧”,竟还心怀叵胎

四象八卦
2024-06-20 16:42:28
题目难哭了?南京2024年中小学期末考试试卷来了!

题目难哭了?南京2024年中小学期末考试试卷来了!

南京择校
2024-06-20 22:52:53
涉嫌严重违纪违法!一80后干部被查!

涉嫌严重违纪违法!一80后干部被查!

六安人
2024-06-20 21:37:06
嗯,是梅洛尼不想让冯德莱恩连任!还要注意她、她和她……

嗯,是梅洛尼不想让冯德莱恩连任!还要注意她、她和她……

新民周刊
2024-06-20 10:05:43
复旦毕业生打老师后续:同学曝打人原因,本人发声道歉,评论炸锅

复旦毕业生打老师后续:同学曝打人原因,本人发声道歉,评论炸锅

180°视角
2024-06-20 10:21:17
2024-06-21 10:40:49
IT爱好者小尚
IT爱好者小尚
分享IT教育类信息
630文章数 55关注度
往期回顾 全部

科技要闻

美媒:苹果正与百度阿里百川等谈AI合作

头条要闻

环球:欧盟若对华抡起贸易大棒 中国不会被动挨打

头条要闻

环球:欧盟若对华抡起贸易大棒 中国不会被动挨打

体育要闻

1-0"吊打"意大利 西班牙这就叫冠军相?

娱乐要闻

陈晓惹争议!被曝婚变离家出走冷暴力

财经要闻

普华永道,引火烧身

汽车要闻

售价11.79-14.39万元 新一代哈弗H6正式上市

态度原创

家居
本地
亲子
房产
旅游

家居要闻

自然开放 实现灵动可变空间

本地新闻

2024·合肥印象|用崭新视角对话城市发展

亲子要闻

鸡娃狂潮下的悲剧:北京每年有两万名儿童,走进安定医院

房产要闻

海棠湾!一所重量级国际学校真的来了!

旅游要闻

铁路儿童票新规 已有超4900万小旅客免费出行

无障碍浏览 进入关怀版