记一次 vue3 数组不响应问题的排查,对象也有可能不响应

最近在编程时,遇到了 vue3 数组更新却没有响应的问题,解决后,决定把对这次的问题总结记录下来。

代码重现

项目的代码太复杂了,我做了一个超精简版本的重现代码:

{{ data.list }}

添加

item-service 代码:

// 条目列表缓存对象let _items: string[] | undefined = undefinedtype Listener = (items: string[]) => voidconst listeners: Array = []export async function getItems(): Promise { if (_items) { return _items } // 从服务器请求数据 _items = await doAjax() return _items}export async function addItem(item: string) { const items = await getItems() items.push(item) listeners.forEach(listener => listener(items))}export async function onItemsChange(listener: Listener) { listeners.push(listener)}

item-service 中缓存了列表对象,然后组件中一直使用 item-service 中缓存的这个列表给 data 赋值 ,问题就出在这。

程序调试

vue3 的响应式是通过 Proxy 实现的,我在 onItemsChange 回调时做了调试,下面是 Proxy handler 的 set 方法的调试过程。为了方便查看,调试中没有被执行到的代码都注释掉了,并且加了一些说明。

// 注释掉的代码都是调试过程中没有被执行的代码function set(target, key, value, receiver) { // 代理 handler 的 set 方法参数说明: // target 原始对象,getItems() 返回的 list // key 属性名称,‘list’ // value 要设置的值,onItemsChange 回调的 list 对象 // receiver 最初被调用的对象,通常是 proxy 本身,这里就是 data.list, list的代理对象 let oldValue = target[key]; // 使用 shallowReactive 的情况下 shallow 标记是 true ,这里是 false if (!shallow && !isReadonly(value)) { value = toRaw(value); oldValue = toRaw(oldValue); // export const isArray = Array.isArray // !isArray(target) 返回 false if (!isArray(target) && isRef(oldValue) && !isRef(value)) { // oldValue.value = value; // return true; } } const hadKey = isArray(target) && isIntegerKey(key) // isIntegerKey(key) 返回 false,下行不执行 // ? Number(key) !Object.is(value, oldValue) // value 和 oldValue 是同一个 list 数组对象, hasChanged 返回 false // trigger(target, “set” /* SET */, key, value, oldValue); } } return result;}

可以看到没有触发任何更新,因此没有响应。

原因总结

原因总算确定了,其实就是因为被代理的数组,和要赋值的数组是同一个数据,在 Proxy 的回调中判定值没有改变,没有触发更新。

// data.list 是 list 的代理对象,将 data.list 提取原始值(toRaw)就是 listdata.list = list

处理的方法也比较简单,将数组简单的克隆下,就没有问题了。

getItems().then((res) => data.list = […res]).catch(console.error)onItemsChange((list) => data.list = […list])

还可以将 item-service 中返回的列表直接克隆。

我这种情况是由于缓存数据共享对象引起的,对于需要共享数据的项目,还可以使用状态管理组件,vuex 或 pinia。

对象是否也有同样问题?

既然是因为复用数组,代理回调因为值没有改变最终没有触发更新,那么对象是否也存在这样的问题呢,我写了个简单的代码验证了下:

{{ data.user }}

change age

答案是肯定的,问题仍然存在。如果存在这种情况,可以将对象克隆(使用 Object.assign() 或其它的方法)得到一个新的对象,再给响应式数据赋值来解决。

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
用户投稿
上一篇 2022年6月14日 06:30
下一篇 2022年6月14日 09:07

相关推荐

  • 分享4条发微商朋友圈的方法(微商朋友圈应该怎么发)

    对于微商朋友来说,朋友圈的重要性不言而喻了。 那么微商的朋友圈到底该怎么发呢? 为什么同样是经营一个朋友圈,有的微商看起来逼格满满,实际效果也不错;而有的却动都不动就被屏蔽甚至拉黑…

    2022年11月27日
  • 存储过程语法(sql server存储过程语法)

    今天小编给各位分享存储过程语法的知识,其中也会对sql server存储过程语法进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧! oracle存储过程基本语法…

    2022年11月26日
  • 《宝可梦朱紫》梦特性怎么获得?隐藏特性获取方法推荐

    宝可梦朱紫里有很多宝可梦都是拥有梦特性会变强的宝可梦,很多玩家不知道梦特性怎么获得,下面就给大家带来宝可梦朱紫隐藏特性获取方法推荐,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 …

    2022年11月25日
  • 《宝可梦朱紫》奇鲁莉安怎么进化?奇鲁莉安进化方法分享

    宝可梦朱紫中的奇鲁莉安要怎么进化呢?很多玩家都不知道,下面就给大家带来宝可梦朱紫奇鲁莉安进化方法分享,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 奇鲁莉安进化方法分享 奇鲁莉安…

    2022年11月25日
  • 什么是推广cpa一篇文章带你看懂CPA推广渠道

    CPA渠道 CPA指的是按照指定的行为结算,可以是搜索,可以是注册,可以是激活,可以是搜索下载激活,可以是绑卡,实名认证,可以是付费,可以是浏览等等。甲乙双方可以根据自己的情况来定…

    2022年11月25日
  • 抖音直播带货有哪些方法技巧(抖音直播带货有哪些痛点)

    如今抖音这个短视频的变现能力越来越突显了,尤其是在平台上开通直播,更具有超强的带货属性,已经有越来越多的普通人加入到其中了。不过直播带货虽然很火,但是也不是每个人都能做好的,那么在…

    2022年11月24日
  • 明查|美国新冠后遗症患者中有16%症状严重以致无法工作?

    点击进入澎湃新闻全球事实核查平台 速览 – 网传数据比例无权威信源佐证,该比例有可能是结合了美国疾病防控中心和布鲁金斯学会的数据得出,但这两个机构的调研目的和样本都不同…

    2022年11月24日
  • 《宝可梦朱紫》暴飞龙怎么抓?暴飞龙获得方法

    宝可梦朱紫暴飞龙位置在哪?在游戏中,很多玩家还不清楚暴飞龙具体要怎么样获得,其实获得方法很简单,暴飞龙直接是没得抓的,需要玩家从宝贝龙进化得到,下面一起来看一下宝可梦朱紫暴飞龙获得…

    2022年11月23日
  • 《宝可梦朱紫》布土拨怎么进化?布土拨进化方法介绍

    宝可梦朱紫中,不同的宝可梦有不同的进化方法,其中布土拨的进化方法是比较特殊的。很多玩家不知道宝可梦朱紫布土拨怎么进化,下面就带来宝可梦朱紫布土拨进化方法介绍,一起来看看吧,希望能帮…

    2022年11月23日
  • 《宝可梦朱紫》薄荷怎么获得?薄荷获得方法

    宝可梦朱紫中薄荷有改变宝可梦的属性或性格等效果,很多玩家想知道宝可梦朱紫薄荷怎么获得,下面就带来宝可梦朱紫薄荷获得方法,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 薄荷获得方法…

    2022年11月23日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息