IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 解决antd mobile的长列表ListView不更新视图问题及源码浅析 -> 正文阅读

[JavaScript知识库]解决antd mobile的长列表ListView不更新视图问题及源码浅析

问题描述:
使用antd mobile 的listview 组件展示列表数据,每个列表项除了展示数据还有一个checkbox,整个列表上方有一个控制checkbox是否显示的按钮,当点击“显示”后,checkbox显示出来,此时上滑列表“加载更多”数据,再点击“隐藏”checkbox,此时的checkbox不消失

解决方法:
需要重新设置dataSource,并且如果是在之前的数据列表的基础上添加的新数据不会导致更新,需要重新深拷贝一份新的数据,即:

//如果是list=[...list,newdata],则需要深拷贝
this.setState({ dataSource: this.state.dataSource.cloneWithRows(JSON.parse(JSON.stringify(list))) })

讨论为什么在旧列表的基础上添加新数据不会更新视图:

切换按钮状态可以触发render方法,但是由于antd-mobile对性能的优化,并不会每次都触发renderRow方法。

关于listview渲染row的过程,需要参考antd mobile的ListView源码中v2.3.0版本中关于ListView的内容,和最重要的rmc-list-view源码,因为antd mobile的listview是在rmc-list-view的基础上封装的,如下所示为antd mobile中Listview的render:
在这里插入图片描述
其中的MListView组件导出自rmc-list-view,在该组件中,关于row渲染的部分在ListView.js中如下所示。其中决定StaticRenderer 组件是否渲染的关键在于shouldUpdateRow变量,根据其取值继续寻找可能导致row不更新的原因

在这里插入图片描述
在这里不去关注rowCount和this._prevRenderedRowsCount的关系(因为和我们这个问题无关),所以需要关注rowShouldUpdate()方法的实现过程,实现过程如下所示。_dirtyRows->needsUpdate变量决定是否需要更新,事实上_dirtyRows中的值正是决定是否更新的关键。
在这里插入图片描述

到此,转换思路,回到问题本身,如果我们设置dataSource的方式是this.setState({ dataSource: this.state.dataSource.cloneWithRows(list) }),可知导致问题的原因一定和cloneWithRows方法有关,因此需要了解cloneWithRows方法做了什么,如下,实际上它调用了另一个方法cloneWithRowsAndSections
在这里插入图片描述

cloneWithRowsAndSections方法中,如下,设置sectionIds和rowIds数组,并对数据进行脏检查,判断数据是否发生变化,设置_dirtyRows的过程就在_calculateDirtyArrays方法中
在这里插入图片描述
_calculateDirtyArrays方法中,判断每一个section中的每一个row是否发生变化,并将结果保存在_dirtyRows中。在判断row是否发生变化的过程中,一方面依据prevRowHash这样一个类似于字典结构的对象来判断该sectionId(rowId)是否已经存在过,另一方面依据_rowHasChanged(也就是我们在构造函数中使用的rowHasChanged方法)方法判断每一个row是否和原来相同,这个方法对我们传入的参数(通常是row1,row2)进行了封装,需要继续查看_getRowData方法
在这里插入图片描述
在ListViewDataSource的构造函数中(也就是我们代码中使用的new ListView.DataSource())对_getRowData方法进行了初始化,默认使用自带的defaultGetRowData方法,而在defaultGetRowData中返回的值是我们给的数据的引用!而我们在list的基础上使用[…list,newdata]方法添加新数据时原本已有的每条数据的引用并没有发生变化(仅限对象数组)。所以当我们使用常用的new ListView.DataSource({rowHasChanged: (row1: any, row2: any) => row1 !== row2})方式来构造dataSource时,非新增数据的row1和row2的引用实际上是一样的,也就是列表没有更新的原因! 也就相当于rows=[{name:'11'}],rows2=[...rows,{name:'22'}],而rows[0]===rows2[0]是一样的原理。
在这里插入图片描述在这里插入图片描述

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:23:40  更:2022-03-15 22:24:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:09:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码