基本每过几个月,市面上就会出现一个新的 Table 组件库。并且拿 Ant Design 的 Table 做一次对比,长此往复。但是有趣的是,往往无论 Table 组件库如何翻新换代。React 下总是难以出现一款让所有人都满意的 Table。今天,我们简单聊聊,为什么 Ant Design 的 Table 这么“慢”。有的是历史问题,而有的则是无奈之举。
在 v4 初期,我们重构了 Table。alpha 的 Table 通过 memo 极致缓存了所有行列数据,基本上来说你怎么折腾。只要data
不变,Table 就不会重新渲染。这很符合大部分场景下的期待,数据没有变当然展示也不用变。但是往往就会有一些 case 会 break 掉这个直觉:
const [count, setCount] = React.useState(0);
const columns = [
{ render: () => count },
];
return <Table columns={columns} {...} />
真实的业务中,有时 Table Cell 不是纯粹的。开发者可以通过render
额外处理一些展示。比如这个例子中,我们简单的将render
设置为外部的 statecount
。这个时候,虽然data
没有变化,但是 Table 还是需要跟随count
做重新渲染。
这种与外部 state 交互的代码很常见,比如说我希望用户点击某一个单元格的时候它可以编辑。所以那个行列可以编辑我存在 state 里。那么这个时候,Table 就不能假设 data 可以推导出 memo 唯一性。那么,是不是columns
相同,且data
相同,那么闭包不会更新我们就可以认为数据不会变呢?当然也是不行的。
let globalValue = 0;
const columns = [{
render: () => globalValue;
}];
export default () => <Table columns={columns} />;
按照useMemo
看,columns
没有变化。但是render
照样可以被改。这个时候,聪明的小伙伴们肯定会想到那我加个和 effect 相似的deps
如何?这样如果deps
变化了,Table 说明需要重新渲染,反之就不需要。很可惜,业务是变化多端的。当你在处理遗留代码时,很难发现因为自己新加的逻辑没有添加到deps
而导致 Table 没有更新。而知识诅咒会使的越聪明的人越难发现这点。他们会更趋向于去阅读源码然后寻找为什么 Table 没有更新。直到找到后,才发现原来这个就存在于文档之上,然后写一篇文章痛斥为什么 Table 要这么过渡设计。
因而在 antd 中,为了让 Table 元素可以 memo。我们提供了一个更原子的shouldCellUpdate
方法。它更贴近渲染,而不是根据deps
来做决定。这样即便聪明人,也能一眼看出是什么导致 cell 被 memo 了。
接着,老生常谈。为什么 Table 不像其他组件一样提供默认的虚拟滚动能力。说真的,我觉得这是 Table 的基础能力。但是它同样也是一个容易埋坑的东东。一个很常见的例子,就是可编辑表格。
在市面上,90% 的 Form 组件都会根据节点自动注册、卸载字段,从而使得开发者不用去关心什么时候字段出现了。它们总是按照预期的收集数据并且提供给开发者。
但是当你支持虚拟表格后,问题便来了。我们知道,虚拟滚动的亮点在于只渲染看得到的部分从而节约大量的节点渲染性能。但是对于 Form 而言,没有渲染的行列也就不会有节点,那么这个字段对于 Form 而言是不存在的。也就是说,当用户辛辛苦苦编辑完一堆内容并提交后。Form 其实只收集了短短几行的数据,其他内容付之东流。(antd 的 Form 可以通过 getFieldsValue(true)
收集所有包括卸载的数据,但是这也能收集到开发者真的不想要的数据)
不同于 Tree、Select 之类的组件,他们的虚拟滚动部分更偏向于数据展示,因而基本不用担心开发者在虚拟滚动中加入副作用。Table 更加灵活,因而如果是可编辑表格往往开发者需要做更耦合的实现来支持虚拟化。
除此之外,还有一些常见的问题。比如超长单元格在滚动到之前不知道它的宽度,因而滚动的时候会突然遇到跳跃的情况。又或者干脆固定宽度失去 Table 原生自适应的能力等等。另外,虚拟滚动对于跨行截断单元格的无障碍支持也会有问题。所以在 antd 中,提供了一个 Demo 关于自行实现虚拟化的功能而没有做成内置的方法。
当然,我还是希望 Table 可以支持虚拟化。只是没有在在想到最好的解法下并不适合立刻动手,以免等到有最优解时又成了历史债务。
在维护大型组件库时,最让人头疼的就是 breaking change。如果你是 antd 的老用户的话,你肯定记得我们有个很蛋疼的 API 叫做feildNames
。是的,它拼错了。于是当我们修正为fieldNames
后,feildNames
仍然保留到整个 major 版本结束。
很多时候,组件库原本的能力是不够的。为此还需要更多的“洞”来支持自定义操作。比如 antd 里常见的xxxRender
系列。Table 也是,如果你观察过,你会发现 Table 的“洞”多如牛毛。基本上所有部件都可以自定义。而随着“洞”的增加,一些原本的 API 又显得很不合理。举个例子。Table 的columns
的render
方法你可以返回节点。同时你也可以返回额外的节点props
:
const columns = [{
render: () => ({
children: 'Hello World',
rowSpan: 2,
colSpan: 2,
});
}];
但是后来,我们又提供了一个onCell
方法,你也可以这么写:
const columns = [{
render: () => 'Hello World',
onCell: () => ({
rowSpan: 2,
colSpan: 2,
});
}];
从开发者角度看,或许这两个差不多。而且原本的render
似乎更内聚一些。但是在实际执行时,它们完全不同。render
返回 props 会导致子节点必然被执行一次。而onCell
可以无关子节点,而只获取 props。后者可以更好的做渲染优化。举一个例子,Hover 行的时候我们会高亮这一行。但是如果这一行是横跨两行的时候,Hover 应该将两行都高亮(而原生 CSS 则很难做到,因而我们需要动态添加className
来实现这个效果):
而无论在动态添加className
还是获取当前 cell 的rowSpan
时,我们都依赖于 props 。通过render
时,则必然需要调渲染 子节点 方法,而在调用渲染 子节点 方法就不能假设没有副作用,因而我们需要将这次的渲染如实反馈到页面上。而后者onCell
则不会有这个问题。
因而在最新版本,我们把所有示例都替换成了onCell
版本。同时提示用户render
返回 props 下个大版本将被废弃。
你会发现,解决某一个单一问题时往往很容易。我们可以针对自己的场景做到极致的优化。但是当业务场景的增加,你的组件库需要考虑的不单单是性能问题。一个更重要的点就是不能因为过渡优化而埋坑。在 Table 上,则是非常典型的取舍问题。因而这是为什么你看到了shouldCellUpdate
而不是自动去 memo。我曾经和一些 Table 的开发者交流过上面的 edge case,但是往往讨论的最终结果就是这个解决了我的问题就行了,所以我不用 antd Table。人人都想要银弹,但是没有银弹。世间充满了不完美。
此外,除了上面几个点之外。Table 在维护过程中也有时候会引入一些真性能问题。比如 context 导致的 rerender、Resizable 导致的 rerender 等等等等。这些遇到就会修掉。本身就是 Table 的 BUG,没什么好说的。以上。
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/3iHmPlWFClIsZGouYjD7vg
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。