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