小知识 : 父组件 的重新渲染会引起子组件 的props发生改变, 所以memo默认是shallow compare
何时使用 : 取消父组件引起的不必要子组件渲染时
针对对象 : memo仅仅针对props, 不会干涉子组件的state或者store或者context引起的渲染
默认比较方法 : shallow compare, 修改:
import { memo } from 'react' ;
const myComponent = ( props ) => { ...}
const areEqual = ( prevProps , nextProps ) => { ...}
export default memo ( MyComponent , areEqual ) ;
讨论前提 : data is immutable
注意事项 : function is mutable
引用比较: 针对0 个{}的有效
浅比较 : 针对只有1 个{}的对象有效
深比较 : 针对大于1 个{}的对象有效
import deepEqual from 'fast-deep-equal' ;
import { equal } from 'fast-shallow-equal' ;
const getType = ( sth ) => {
return Object . prototype . toString . call ( sth ) . slice ( 8 , - 1 ) ;
}
const deepObject = ( obj ) => {
const keys = Object . keys ( obj ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
const type = getType ( obj [ keys [ i ] ] ) ;
if ( type === 'Object' || type === 'Array' ) return true
}
return false
}
export const smartStrictEqual = ( prev , next ) => {
const prevType = getType ( prev ) ;
const nextType = getType ( next ) ;
if ( prevType !== nextType ) return Object . is ( prev , next ) ;
if ( prevType === 'Array' ) return deepEqual ( prev , next ) ;
if ( prevType !== 'Object' ) return Object . is ( prev , next )
if ( deepObject ( prev ) || deepObject ( next ) ) return deepEqual ( prev , next )
return equal ( prev , next )
}
memo在组件Composition模式下的失效问题
// A的re-render会引起B的re-render
const ComponentA = ( ) => (
< ComponentB />
)
// A的re-render不会引起B的re-render
// App的re-render会引起A和B的re-render
const App = ( ) => (
< ComponentA >
< ComponentB />
< ComponentA />
)
内部元素 : A的re-render会引起B的re-render
props传入 :
App 的re-render才会引起B 的re-render,A 不会;
B 的re-render势必引起A 的re-render, 因为B 作为props传入了A
对A 使用memo是无效的,因为children中包含函数,结果一定不同
const C0 = ( props ) => {
return (
< div >
C0 Component
< C1 >
< C2 >
< C3 />
</ C2 >
</ C1 >
</ div >
)
}
背景: 无任何memo
问题: C0 re-render时, 哪些组件会跟着re-render?
分析: C1, C2, C3都会re-render, 因为字面上 ,它们都是C0的子组件
背景: 除C0外全部使用memo, 采用smartStrictEqual方法
问题: C0re-render时, 哪些组件会跟着re-render?
分析:
C3的props中无 children,使用memo能阻止 渲染;
C2的props中有 children,memo无法 阻止渲染;
C1的props中有 children, memo无法 阻止渲染;
解决方案:
自定义比较方法,忽略对children的比较
作为props的函数,在传入前要进行useCallback, 要注意添加适当的deps
Container和Contained之间存在数据传递
灰层数据传入需要通过Container
Container和Contained强 耦合
High Order Component Pattern
High Order Component和Low Order Component之间存在数据传递
灰层数据传入需要通过High Order Component
High Order Component和Low Order Component低 耦合
能够优雅地多层嵌套
Provider和Render Component之间存在数据传递
灰层数据传入无需 经过Provider层中继
Provider和Render Component低 耦合
多层嵌套可以说是非常丑陋
可读性很强,能够一眼看出组件间的关系
Composite Component Pattern
Parent和Children之间不存在数据传递
灰层数据传入无需 经过Provider层中继
Parent和Children弱 耦合
可以优雅地多层嵌套,就像HTML一样
可读性强