- 小知识: 父组件的重新渲染会引起子组件的
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)
}
- 作为内部元素
// A的re-render会引起B的re-render
const ComponentA = () => (
<ComponentB/>
)
- 作为
props
传入
// 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
和Low Order Component
之间存在数据传递灰层数据
传入需要通过High Order Component
High Order Component
和Low Order Component
低耦合
- 能够优雅地
多层嵌套
Provider
和Render Component
之间存在数据传递灰层数据
传入无需经过Provider
层中继Provider
和Render Component
低耦合
- 多层嵌套可以说是非常丑陋
可读性
很强,能够一眼看出组件间的关系
Parent
和Children
之间不存在数据传递灰层数据
传入无需经过Provider
层中继Parent
和Children
弱耦合
- 可以优雅地
多层嵌套
,就像HTML
一样 - 可读性强