小知识 : 父组件 的重新渲染会引起子组件 的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
方法
问题: C0
re-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
一样
可读性强