渲染控制流程图
知识点
问:**render **
阶段作用详解?
答:在组件一次更新中,类组件执行 render
,函数组件执行renderWithHooks
(renderWithHooks
中执行函数组件本身),他们的作用是什么?真实渲染 DOM 了吗?真实 DOM 是在 commit 阶段挂载的。**render**
函数作用,根据一次更新产生新的状态值,通过 React.createElement
,替换成新的状态,得到新的 React element 对象,新的 element 对象上保存了新的状态值。createElement
会产生一个全新的 props
。到此 render 函数完成任务。
接着 React 会调和由 render 函数产生的 children,将子代 element 对象变为 fiber(此过程若存在 alternate,将复用 alternate 进行克隆,若不存在,创建 alternate),将 props 变为 pendingProps,至此当前组件更新完成。然后,若 children 是组件,重复上步骤,直到调和完成。完成 render 阶段。
问:什么是**alternate**
TODO???
问:**useMemo**
详解?
语法:const cacheSomething = React.useMemo( create, deps )
create
:函数,函数的返回值作为缓存值,React element 对象也可作为缓存值(如:useMemo(() => <xxxComponent/>, deps)
)。deps
:依赖项,若依赖项变化,缓存值更新;cacheSomething
:返回值,执行create
函数后的返回值,若deps
改变,返回重新执行的create
函数的值,否则取上一次缓存的值。
useMemo
原理 - TODO:
- 联系:函数组件对应的 fiber 对象,fiber 对象是依组件级别创建的???
useMemo
应用场景:
- 可缓存 element 对象,从而达到条件渲染组件,优化性能;
- 可缓存一些不是每次 render 都需要计算的值;
- 可将属性、方法缓存起来,作为
PureComponent
的绑定方法,或配合其他 Hooks 一起使用。
问:为什么将 Element 对象缓存起来,就实现了控制子组件不必要的渲染?
答:每次执行render
本质上createElement
会产生一个新的props
,新的props
会作为对应 fiber 的pendingProps
,在此 fiber 更新调和阶段,React 对比 fiber 上 老oldProps
和 新newProps(pendingProps)
是否相等,若相等函数组件放弃子组件的调和更新,子组件不会重新渲染;若将 Element 对象缓存起来,props
也就和 fiber 上oldProps
指向相同的内存空间,也就相等,从而跳过本次更新。
问:**shallowEqual**
过程?
- 比较新旧
props
或新旧state
是否相等,若相等不更新组件; - 判断新旧
state
或新旧props
有不是对象或为null
的,则直接返回false
,更新组件; - 通过
Object.keys
获取新旧state
或新旧props
属性名key
变成数组,查看数组长度是否相等,相等,不更新组件,不相等,新增或删除,更新组件; - 遍历旧
state
或旧props
判断对应新state
或新props
,有没有与之对应并且相等(相等是浅比较),若有一个不对应、不相等,返回false
,更新组件。
以上就是PureComponent
做渲染节点优化的过程。
问:**useCallback**
和**useMemo**
区别?
答:useCallback
接收两个参数,第一个参数就是需要缓存的函数,第二个参数是依赖项deps
,deps
改变返回新的函数。可用useCallback
来缓存 element 对象。useMemo
接收两个参数,第一个参数是一个函数,需要执行这个函数,函数的返回值为缓存的内容,比起useCallback
,useMemo
更像是缓存了一段逻辑,或说这段逻辑执行获取到的结果。
问:memo 主要逻辑?
答:
- 依
memo
的第二个参数,判断是否执行更新,若无第二个参数,以浅比较 props 为diff
规则。若相等,当前 fiber 完成工作,停止向下调和节点,所以被包含的组件不更新。 memo
可理解为 HOC,它的阻断更新流程的机制,是通过控制下一级 children ,也就是memo
包裹的组件,是否继续调和渲染,来达到目的。- 禁用
const newIndex = React.memo(() => true)
来阻断渲染。
精选评论
渲染控制的常见情形有:包含图片等资源的列表。
加 key,避免 prop 的不必要更新,
特别注意的是列表项含有用户交互事件,传给 onClick 事件等的 prop,不能直接使用 (item) => { },不然每次列表项都是新的 prop,不断触发列表项渲染,几十项的图片等资源,很耗性能。
可以用 this.method 或 useCallback,根据 index, 在函数里再去取对应 item。
渲染劫持方案: