React Hooks 与 Immutable 数据流实战 Review
reconciliation
减少渲染
shouldComponentUpdate
会在 props or state 发生变化时返回 true,表示组件重新渲染,从而调用render,控制VDOM的diff过程
节点类型相同 返回false 不需要对子节点进行比较,否则遍历
节点不同,直接删除,后替换
一般 scu 会比较props和state中是否发生变化 浅比较,判断是否为true,触发reconciliation, ex purecomponent api
React dom diff
- 只比较同层节点,不会跨层比较节点
- 不同两个节点产生不同的树,类型不同,原来节点后的全部替换
- 通过key指定哪些元素相同
执行流程
-
元素不同类型 略
-
相同类型
2.1 都是dom节点,对比节点className 等属性,处理完后,对子节点递归
2.2 组件元素 实例不变,更新props。调用组件实例的componentWillReceiveProps方法,通过,scu 返回值判断是否要调用render
处理完成后对子节点进行递归
2.3 特殊情况 遍历子元素列表
引入key 值,通过key判断是否存在,如果只是位置调换,只用调节位置,不用更新整个节点
key选取 必须列表唯一
其实memo就是一个语法糖,内部实现也是基于PureComponent的,创建了个新的类组件继承下PureComponent
列表渲染,key 属性的值 的最佳实践是什么?
前后端协作,后端指定唯一标识,前端设置这个标识为key
除了常见的渲染列表,我们需要增加key属性;还有什么其他场景,我们需要主动增加key这个属性呢?
假如有一个带开场动画的弹窗,弹窗在这个页面的生命周期需要多次展现消失,如果没有key,第二次弹窗展现的时候,不会有动画效果
不是很明白为什么比较两个树时间复杂度要O(n^3),能写一下具体的比较代码吗..
求两棵树的编辑距离。代码不写了,给你一些链接参考吧。 什么是编辑距离? ![https://leetcode-cn.com/problems/edit-distance/](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgdmlld0JveD0iMCAwIDE4IDE4Ij4KICAgIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDI3RkZGIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iLjgxOCI+CiAgICAgICAgPHBhdGggZD0iTTguMDMgNS4yNzZsMS41ODUtMS41ODRjMS4wOTMtMS4wOTMgMi45My0xLjAzIDQuMS4xNDEgMS4xNzIgMS4xNzIgMS4yMzYgMy4wMDguMTQyIDQuMTAyTDEyLjY3IDkuMTIzbC0uNzkyLjc5MmMtMS4wOTMgMS4wOTMtMi45MyAxLjAzLTQuMS0uMTQyIi8+CiAgICAgICAgPHBhdGggZD0iTTkuMjE5IDEyLjU3M2wtMS41ODQgMS41ODRjLTEuMDk0IDEuMDk0LTIuOTMgMS4wMy00LjEwMi0uMTQxLTEuMTcxLTEuMTcyLTEuMjM0LTMuMDA4LS4xNDEtNC4xMDFMNC41OCA4LjcyN2wuNzkyLS43OTJjMS4wOTMtMS4wOTQgMi45My0xLjAzIDQuMTAxLjE0MSIvPgogICAgPC9nPgo8L3N2Zz4K)leetcode-cn.com diff 如何从O(n^3)到 O(n)? ![https://www.zhihu.com/question/66851503](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgdmlld0JveD0iMCAwIDE4IDE4Ij4KICAgIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDI3RkZGIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS13aWR0aD0iLjgxOCI+CiAgICAgICAgPHBhdGggZD0iTTguMDMgNS4yNzZsMS41ODUtMS41ODRjMS4wOTMtMS4wOTMgMi45My0xLjAzIDQuMS4xNDEgMS4xNzIgMS4xNzIgMS4yMzYgMy4wMDguMTQyIDQuMTAyTDEyLjY3IDkuMTIzbC0uNzkyLjc5MmMtMS4wOTMgMS4wOTMtMi45MyAxLjAzLTQuMS0uMTQyIi8+CiAgICAgICAgPHBhdGggZD0iTTkuMjE5IDEyLjU3M2wtMS41ODQgMS41ODRjLTEuMDk0IDEuMDk0LTIuOTMgMS4wMy00LjEwMi0uMTQxLTEuMTcxLTEuMTcyLTEuMjM0LTMuMDA4LS4xNDEtNC4xMDFMNC41OCA4LjcyN2wuNzkyLS43OTJjMS4wOTMtMS4wOTQgMi45My0xLjAzIDQuMTAxLjE0MSIvPgogICAgPC9nPgo8L3N2Zz4K)www.zhihu.com
优化方案
一、purecomponent memo 进行浅比较
// shallowequal
// is(a,b) // 第一关:基础数据类型直接比较出结果
// typeof a,b must object // 2 必须是obj
// hasOwnProperty.call(b,keysa[i]) // 3 属性的长度进行比较 4 type比较 // 浅比较
// 调用 state.a.push("2") 一旦属性的值为引用类型的时候浅比较就失灵了。
state: {a: ["1"]} -> state: {a: ["1", "2"]}
// 由于js 引用赋值,浅比较无法使用复杂结构组件
二、scu deep comp
else { // 最后一次比较后添加对值的递归比较
if (!deepEqual (objA [keysA [i]], objB [keysA [i]])){
return false;
}
}
// 样就达到了深层比对的效果。但是想想一种极端的情况,就是在属性有一万条的时候,只有最后一个属性发生了变化,那我们就不得已将一万条属性都遍历。这是非常浪费性能的。
三、immutable数据结构 scu memo浅层对比
回到问题的本质,无论是直接用浅层比对,还是进行深层比对,我们最终是想z知道组件的 props (或 state) 数据有无发生改变。
immutable 数据一种利用结构共享形成的持久化数据结构,一旦有部分被修改,那么将会返回一个全新的对象,并且原来相同的节点会直接共享
是吧!只更新了父节点,比直接比对所有的属性简直强太多,并且更新后返回了一个全新的引用,即使是浅比对也能感知到数据的改变。
immutable 也有一些被部分开发者吐槽的点,首先是 immutable 对象和 JS 对象要注意转换,不能混用,这个大家注意适当的时候调用 toJS 或者 fromJS 即可,问题并不大。
基本设计immutable api
fromJS
toJS
get/getin
set
merge
三元老师,下面是我的一些理解,优化方案二对 pureComponent 浅比较进行优化,以避免 state.a.push("a")
这样的操作造成错误。方案二的设计目的为了达到深层次的比较,以判断引用相同时对象的差异。但实际上,如果引用未发生变化,我们访问到的是同一个对象值,无法跟踪变更。相同引用的属性指向的对象始终是同一个对象,换句话说,我们的深层次比较中第四关的递归不过是判断同一个对象的属性值的差异,显然,它们将永远相等。方案二无法解决 pureComponent 渐层比较的问题,我们要想知道数据有无发生改变,必须保证数据的不可变性,从而引入 immutable,我们的方案三。
不是你这样理解的,浅拷贝对比的是对象的引用,所以浅比较无效;而递归调用比较函数实现的是在对象本身而非引用上进行比较,也就是对比对象的属性和值,这就是深层比较。用方案三只是为了时间考量
immutable这个库是不是有点太重了,如果只是做浅比较防止过度刷新的化,immer更合适些。
是,在ts分支中我已经用immer重构了
总结起来就是想在对react组件进行性能优化时,需要监测state或props的变化来判断是否render,而怎么监测变化=>用浅比较,但浅比较存在更新对象属性时引用没变的问题,所以只要能解决这个问题,浅比较依然是好方案,因此immutable的出现解决的就是有变化就返回新引用,故而浅比较+immutable就是性能优化的利器,然后后面出现的Immer是比immutable更好的方案
大数据量的情况下,序列化一次带来的性能消耗可能比重新diff还大
immutable.js确实有这个问题。用immer更好
请问大佬,直接用JSON.stringify比较的缺点是什么
每次都是不一样的引用,无论如何都刷新