一、前言

最近因为项目要求,开始学习并且使用React和Ant Design框架。在前端开发过程中,遇到这样一个页面:有多个tab,每个tab下都是一个table表格来进行数据展示。但,每个table的title都是一样的,如何进行表格的渲染和对应数据的展示就值得开发人员考虑。下面,我们一起来瞧瞧。

二、性能优化和逻辑分析

2.1、性能优化

在开发中,最大程度上对性能进行优化,是开发人员的不懈追求。对于前端开发而言,操作尽可能少的DOM的,是页面性能优化的一个重要部分。
为什么这样说呢,来看看下面这个简化版的,浏览器输入url到网页显示的整个过程就明白了:

  • 浏览器输入url并回车
  • 域名解析
  • 发起TCP三次握手
  • 发送HTTP请求
  • 服务端响应请求,浏览器得到html代码
  • 浏览器解析html代码,并请求html代码中的资源
  • 页面渲染呈现给用户

“页面渲染呈现给用户”这最后一步,又是这样一个过程:

  • 浏览器把获取到的html代码解析成1个DOM树,html中的每个标签都是DOM树中的一个节点,根节点就是document对象。DOM树中包含了所有html标签
  • 浏览器解析所有样式(解析成样式结构体:CSSOM树),在解析的过程中去掉浏览器不能识别的样式
  • DOM树和CSSOM树组合后构建render tree
  • 等render tree构建完成后,计算像素坐标等一些列准备工作
  • 浏览器根据此来绘制页面

那么,既然每个table的title都一样,只是渲染的数据有不同,基于性能优化的考虑,我让这个页面的每个tab都共用一个table,每次点击不同的tab,根据此tab的key值,调用不同的后端数据接口,处理数据并完成数据更新。
这样,最大程度的减少了DOM的渲染,达到性能优化的目的。能推出,这个table表格越复杂,优化的效果越好,因为减少了更多重复的DOM渲染(这是不必要的)。

2.2、逻辑分析

既然已经从性能优化角度分析除了最好的方式是减少DOM渲染,那么,最直接的方法就是,在react的对应组件中(主要使用了antd的Tabs、Table组件),直接让Table组件和Tabs组件平级即可。为了更清楚,直接上代码:

//  我用的是函数组件
import { ..., Table, Tabs, ... } from 'antd';
import React, { useEffect, ..., useState } from 'react';
...
const onChange = (key: string) => {if (key === '1') {//  这里写调用接口和处理数据的逻辑代码...}else if key === ‘2’) {//  这里写调用接口和处理数据的逻辑代码...}...
}
...
const App: React.FC = () => {...return (//  让Table组件和Tabs组件平级(这里的结构是关键)<><Tabs defaultActiveKey="1" onChange={onChange}>...<Tabs/><Table columns={columns} dataSource={tableData} />...</>)
}

三、遇到的问题及解决

大的思路想好之后,代码开发过程中,我在更新Table的datasource过程中又遇到了问题。预想的是,进入到这个页面时,默认选中第一个tab,调第一个tab的数据接口,然后将数据赋值给Table的datasource,让表格对其进行展示。

3.1、遇到的问题

1、写在useEffect中的接口调用,通过浏览器控制台的Network,看到这个接口在不断的调用,导致点击别的tab,数据在瞬间更新后又被useEffect钩子中的第一个tab数据冲掉;

2、datasource数据赋值成功了,但是Table表格中数据却没有更新。

3.2、问题分析

问题1:useEffect的函数在不断地被执行,导致同一个接口被不断的调用,我第一反应就是去查阅useEffect钩子的说明文档,果然被我找到了原因,下面贴几张官方文档的截图来说明:


下面这张图是最主要的原因

问题2:Table的dataSource 更新,Table未重新渲染。为什么React不重新渲染DOM呢?从这个思路出发,在查阅了React的DOM的重新渲染及之后,在看我的给datasource赋值代码,(才开始,我没有用useState钩子函数,而是直接定义了一个空数组变量给datasource使用)发现了问题:

//  这是我有问题的赋值代码:
...
const tab2Datasource = async () => {const apiRes = await 接口调用函数名;if (apiRes) {//  假设这块的apiRes已经被我处理成我需要的数据格式了//  注意这块的赋值代码,我是直接“=”赋值的,对于数组这种复杂数据类型来说,这只是改变了它在栈内存中的指针,并没有实质性的改变其堆内存中的数据。//  但就是因为指向了一个地址,React认为虚拟DOM并没有改变,因此,不会重新渲染页面。//  这就会导致Table组件的dataSource改变了,但是Table并没有重新渲染tableData = apiRes}
}
...

3.3、问题解决

再分别找出bug的原因之后,修改起来就很简单了。直接上代码:
问题1:解决接口函数在useEffect钩子中被无限调用的问题

//  这是原来的bug代码:useEffect(() => { tab1Datasource() });//  给useEffect钩子中加上空数组的参数即可useEffect(() => { GetMyToDoFlowList() }, []);

问题2:解决datasource数据更新了但Table不更新的问题

//  原来的bug代码
见“3.2、问题分析”的代码
//  成功修改Bug后的代码
...
import React, { useEffect, ..., useState } from 'react';
...
const App: React.FC = () => {...//  1、使用useState钩子函数const [tableData, setTableData] = useState(Array);//  2、重新改变数组的赋值方式//  解决原理也很简单,新建一个Array指向不同地址,再赋值,这样React就会认为需要重新渲染Table了const tab2Datasource = async () => {const apiRes = await 接口调用函数名;if (apiRes) {const tableDatas: DataType[] = [];const datas: DataType[] = [{key: '1',name: 'John Brown',age: 32,address: 'New York No. 1 Lake Park',},...];datas.forEach((item) => {tableDatas.push(item);});setTableData(tableDatas);} else {console.log('代办工作数据请求失败!!!');}};
}

四、说明

参考链接:
React官方文档之使用 Effect Hook
JS的浅拷贝和深拷贝的剖析以及部分实现方法
React Table dataSource 更新,Table未重新渲染

欢迎大家一起讨论、学习

react-antd项目,一个多tab页面,共用一个title相同的table表格,并且在切换tab时实现数据更新相关推荐

  1. 记一次webpack4+react+antd项目优化打包文件体积的过程

    背景 最近自己整了一个基于webpack4和react开发的博客demo项目,一路整下来磕磕碰碰但也实现了功能,就准备发到阿里云上面去看看,借用了同事的阿里云小水管服务器,配置完成之后首页加载花了十几 ...

  2. umi搭建react+antd项目(一)环境配置

    1.先创建文件夹,windows用户手动创建就行了 mkdir myReact && cd myReact 2.在myReact目下,执行脚手架命令,默认选择antd yarn cre ...

  3. umi搭建react+antd项目(五)子组件编写

    上一篇在index.js里面写了一个组件,不是很友好,我们现在分开写组件 1.新建component文件夹用于放置组件,src/component,新建list组件 import React, {Co ...

  4. umi搭建react+antd项目(二)路由

    1.我们在src下新增index2.js: import React, {Component} from 'react';export default class index2 extends Com ...

  5. 微信小程序多页面共用一个数据globalData,并及时同步更新各页面的数据的做法

    使用场景:比如有A.B.C 三个页面都有收货地址这么一个数据,这个收货地址的数据源是一样的,而这3个页面都可以独立修改收货地址.在其中一个页面修改收货地址后,另外两个页面的收货地址数据也要同步更新. ...

  6. umi搭建react+antd项目(六)父子组件通讯

    上一篇写了一个子组件,只是把值传入进来,这篇讲解在子组件修改父组件的数据 1.在index.js里,新增方法:updateImg 用于修改list集合 updateImg() {this.setSta ...

  7. umi搭建react+antd项目(四)axios请求数据

    1.下载axios yarn add axios 2.在src下新建文件夹conf,再新增js文件:axiosConf.js import axios from 'axios'axios.defaul ...

  8. umi搭建react+antd项目(三)Mock 数据--模拟数据

    1.添加mockjs yarn add mockjs 2.在mock目录下新建test.js List|10,返回list,10条数据 @image,随机生成img的url链接,mock内置函数 im ...

  9. 上一个淘宝页面附带一个登陆界面

    用到的是css定位较多,js的响应事件一点 <!DOCTYPE html> <html lang="en"> <head><meta ch ...

最新文章

  1. Co-Fusion:物体级别的语义SLAM
  2. 基于自编码器的表征学习:如何攻克半监督和无监督学习?
  3. Android基础——数据持久化存储
  4. 【算法】K-Means聚类算法(k-平均或k-均值)
  5. 5 交换机-direct (路由)
  6. 在CentOS7下安装MySQL8数据库
  7. 华为正式发布鸿蒙OS操作系统,分布式架构首次用于终端
  8. html新建盒子,html+css 盒子模式展示(备查)
  9. 【图像去噪】基于matlab GUI多种滤波器图像去噪【含Matlab源码 1778期】
  10. python关于sjis编码的错误
  11. 中国内蒙古医企在“吴哥国际医院”开展“千人一对一国际医疗捐助”
  12. 作为Fab-Liter战略的一部份,安森美剥离晶圆制造厂
  13. Excel 阅读模式 高亮标记 聚光灯效果 “完美“解决方案
  14. JDBC、封装JDBC连接池、第三方连接池工具
  15. 机器学习-雅可比式与多元高斯分布
  16. Edgedetect 边沿检测(Verilog)
  17. android compose webview视频播放横竖屏切换
  18. 几种生态廊道构建概念、方法和工具的本质比较
  19. Connected to the target VM, address: ‘127.0.0.1:62401‘, transport: ‘socket‘ 问题几种解决办法
  20. 合理构建产品形态(一)——谁是目标用户

热门文章

  1. CentOS 端口转发
  2. 网络协议系列之二:HTTP(2)
  3. 项目管理,时代的召唤——专访清晖创始人傅永康
  4. ln火线零线_LN哪个代表零线哪个代表火线
  5. linux tar包分隔 tar split
  6. html九宫格布局原理,CSS九宫格布局
  7. 联想拯救者R270笔记本安装双系统Win10+Ubuntu16.04
  8. python使用m3u8库解析m3u8文件
  9. SAP BO/BusinessObjects视频培训教程
  10. windows环境下下tomcat服务搭建