react dom的diff理解及性能优化

2023-12-13 03:30:17

diff的三大过程

当某个值变化时,他从根组件寻找
(key,state,props,context)
当父组件稳定时,react会跳过子组件的props的对比
只有当当前组件值改变时,从他开始,所有的子孙节点都会对比props
props是全等比较,所以,都会触发重新渲染

(比如把组件A移动到父组件的某个兄弟节点位置,
那么我diff的过程中,如何寻找这个组件呢,就必须跨层级递归寻找
非常耗性能)

所以,React假设,没有跨层级的移动组件
(因为实际开发中跨层级的移动组件确实极其的少)
所以diff就可以只比较同级的节点,性能从O n^3 变O n

在 React 15 中是递归处理虚拟 DOM 的,
React 16 则是变成了可以中断的循环过程,
	Scheduler 调度器 —— 收集变化 调度任务的优先级,高优任务优先进入 Reconciler
	Reconciler 协调器 —— 负责找出变化的组件 diff算法  可中断
	Renderer 渲染器 —— 负责将变化的组件渲染到页面上


Fiber 架构的核心即是"可中断"、"可恢复"、"优先级"
作为静态的数据结构来说,每个 Fiber 节点对应一个 React element,
保存了该组件的类型(函数组件/类组件/原生组件等等)、对应的 DOM 节点等信息。
作为动态的工作单元来说,每个 Fiber 节点保存了本次更新中该组件改变的状态、要执行的工作

Fiber 把一个渲染任务分解为多个渲染任务,
而不是一次性完成,把每一个分割得很细的任务视作一个"执行单元"

React 16 则是变成了可以中断的循环过程,

每次循环都会调用shouldYield判断当前是否有剩余时间。
requestIdleCallback回调的执行的前提条件是当前浏览器处于空闲状态 去中断
然后	新一轮的调度开始

useMemo

https://juejin.cn/post/7253980320357269561?searchId=20231209154011153FF01F950F1F4D3A93#heading-2

 const childFucntion = useCallback(() => {
    action()
 }, [a, b])
作用:用于优化渲染性能。

useMemo 会接收一个箭头函数包裹的回调函数和依赖项数组,然后返回回调函数的计算结果。
当依赖项数组中的某个值发生变化时,useMemo 会重新计算回调函数。

如果依赖项没有发生变化,useMemo 会返回上一次计算的结果,
这样可以避免不必要的计算。

如下,只有在a或者b发生改变的时候,value的值才会重新计算。



useCallback
 const childFucntion = useCallback(() => {
    action()
 }, [a, b])
 
 当依赖数组中的值发生变化时,useCallback 会返回一个新的函数实例。
 否则,它将返回上一次创建的函数实例
他俩是如何做性能优化的呢
当你去改变父组件中的state,就会导致父组件重新构建,
而父组件重新构建的时候,会重新构建父组件中的所有函数
(旧函数销毁,新函数创建,等于更新了函数地址),
新的函数地址传入到子组件中被props检测到栈地址更新。
也就引发了子组件的重新渲染。

useCallBack并不能阻止函数重新创建
,它只能通过依赖决定返回新的函数还是旧的函数,
从而在依赖不变的情况下保证函数地址不变
useCallBack需要配合React.memo使用
useMemo会执行回调函数并且返回结果,
但是useCallback不会执行回调函数。

他俩都需要 结合React.Memo进行使用

useEffect

useEffect(()=>{},[])

setTimeout(()=>{
	dosomesing
},0)

文章来源:https://blog.csdn.net/qq_36262295/article/details/134897300
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。