
React | React Native
文章平均质量分 90
Wang's Blog
Keep learning for the innovation era.
展开
-
React18源码: Fiber树的初次创建过程图文详解
首先我们有一个探寻的过程,首先探寻到App,然后从App到div,再到 header,发现没有子元元素了所以到 Content,到Content之前会做一件事情,就是把它自己需要的dom,在内存中创建出来包括包含的哪些属性也创建出来,生成一个effect的一个属性,合并到div里面去这个就是说白了,探寻到header, header进行回溯,我在内存中创建了一些东西因为这个在更新的时候要用,总得找个地方存起来,存起来的东西就叫做 effect存在哪里呢?原创 2024-02-25 14:23:28 · 1586 阅读 · 0 评论 -
React18源码: Fiber树中的优先级与帧栈模型
针对fiber对象或update对象,只要它们的优先级(如:fiber.lanes和update.lane)比渲染优先级低,都将会被忽略。在前文 double buffering 中分析过,HostRootFiber.alternate 是正在构造的fiber树的根节点。可以看到,无论是应用初始化或者发起组件更新,创建update.lane的逻辑都是一样的。此处返回的lanes会作为全局渲染的优先级,用于fiber树构造过程中。所以每次fiber树构造是一个独立的过程,需要独立的一组全局变量。原创 2024-02-24 12:19:53 · 1031 阅读 · 0 评论 -
React18源码: Fiber树中的全局状态与双缓冲
从React工作循环的角度来看,整个构造过程被包裹在fiber树构造循环中(对应源码位于ReactFiberWorkLoop.js).比如说:Legacy模式下的首次更新,不会经过调度中心(第2阶段)而是直接进入fiber树构造(第3阶段).在源码中,大部分变量都带有英文注释(读者可自行查阅),此处只列举了fiber树构造循环中最核心的变量。1 )构造过程中,fiberRoot.current 指向当前界面对应的fiber树。fiber树的构造过程,就是把ReactElement转换成fiber树的过程。原创 2024-02-24 10:13:00 · 1235 阅读 · 0 评论 -
React18源码: task任务调度和时间分片
创建任务之后,最后请求调度 requestHostCallback(flushwork)(创建任务源码中的第5步)现在再次回到 react-reconciler包中,在调度过程中的关键路径中,还需要理解一些细节。1.在task注册完成之后,会设置fiberRoot对象上的属性,代表现在已经处于调度进行中。在 Renconciler 运行流程中总结的4个阶段中,注册调度任务属于第2个阶段。调度的目的是为了消费任务,接下来就具体分析任务队列是如何管理与实现的。这2大特性的实现,都集中于这个while循环。原创 2024-02-23 19:45:51 · 1387 阅读 · 1 评论 -
React18源码: schedule任务调度messageChannel
看完这8个内部函数,最后浏览一下完整的 performWorkUntilDeadline 回调的实现。调度中心最核心的代码,在 SchedulerHostConfig.default.js 中。这4个函数代码都很简洁,其功能在注释中都有解释.1 )调度相关:请求或取消调度。原创 2024-02-23 17:28:33 · 1421 阅读 · 0 评论 -
React18源码: React中的LanePriority和SchedulerPriority
reactPriorityLevel, 属于react-reconciler包,定义于 SchedulerWithReactIntegration.js中。与fiber构造过程相关的优先级(如fiber.updateQueue,fiber.lanes)都使用LanePriority.为了能协同调度中心(scheduler 包) 和 fiber树构造(react-reconciler包)中对优先级的使用。由于本节重点介绍优先级体系以及它们的转换关系,关于Lane(车道模型)在fiber树构造时使用。原创 2024-02-23 13:30:04 · 1440 阅读 · 1 评论 -
React18源码: React调度中的3种优先级类型和Lane的位运算
可以看得出来lane&-lane的结果是SyncLane,所以通过lane&-lane就能分离出最高优先级的任务。即A(cpu)>B(IO)>C(cpu).此时的需求需要将任务B从group中分离出来,先处理cpu任务A和C。在新版本的React中,还有一个新特性,就是render阶段可能被中断,在这个期间会产生一个更高优先级的任务。如上就是通过 lanes & -lanes 分离出最高优先级的任务的,我们来看一下具体的流程。也即是说lane的代表的数值越小,此次更新的优先级就越大。原创 2024-02-23 11:52:46 · 1823 阅读 · 0 评论 -
React18源码: reconcliler启动过程
新建的fiber节点,其mode来源于父节点,所以HostRootFiber.mode非常重要。注意:fiber树中所有节点的mode都会和HostRootFiber.mode一致。最后会创建fiberRoot对象(在这个过程中,特别注意RootTag的传递过程)在createFiberRoot中,创建了 react应用的首个fiber对象。运行到这里,3个对象创建成功,react应用的初始化完毕。核心流程图如下,其中红色标注了3个对象的创建时机。这3个对象是react体系得以运行的基本保障。原创 2024-02-23 09:26:33 · 1380 阅读 · 0 评论 -
React18源码: reconciler执行流程
与输入环节紧密相连,scheduleUpdateOnFiber函数之后,立即进入 ensureRootIsScheduled 函数。在 react-reconciler 对外暴露的api函数中,只要涉及到需要改变fiber的操作(无论是首次渲染或后续更新操作)performConcurrentWorkOnRoot 的逻辑与 performSyncWorkOnRoot 的不同之处在于。在ReactFiberWorkLoop.js中,承接输入的函数只有scheduleUpdateOnFiber。原创 2024-02-22 21:45:57 · 1263 阅读 · 0 评论 -
React18原理: React核心对象之Update、UpdateQueue、Hook、Task对象
updateQueue是fiber对象的一个属性,它们之间数据结构和引用关系如下。注意task中没有next属性,它不是一个链表,其顺序是通过堆排序来实现的。小顶堆数组,始终保证数组中的第一个task对象优先级最高。2 )Update对象相关的数据结构。Hook与fiber的关系。原创 2024-02-22 18:12:36 · 1474 阅读 · 0 评论 -
React18原理: React核心对象之ReactElement对象和Fiber对象
连接渲染器(react-dom)和调度中心(scheduler),同时自身也负责fiber树的构造。每个ReactElement对象的区别在于type不同,其type定义在shared包中。及其所有子节点都是ReactElement对象(在render之后才会生成子节点)先看数据结构,其type类型的定义在 ReactInternalTypes.js 中。所有采用jsx语法书写的节点,都会被编译器转换,最终会以。创建出来一个与之对应的ReactElement对象。可以简单的认为,包括。原创 2024-02-17 15:30:51 · 1622 阅读 · 0 评论 -
React18原理: 核心包结构与两大工作循环
react中的工作循环,这是它的一个最顶层的一个流程图,在这张图里面,有两个核心的大循环,第一大循环是 react-reconciler 提供的,它的核心是构建fiber树,生成任务,第二大循环是 scheduler 提供的, 它的核心是任务调度(处理任务的优先级),react的原理实际上就是两大工作循环原创 2024-02-13 22:46:26 · 1938 阅读 · 0 评论 -
React18原理: 时间分片技术选择
/ 内部再调用 n-1次 loop,总计调用 n 次 loop。可以看到,圈中的部分,明显被阻塞,这一块绝对会导致用户体验很差。1 次完成 1w 个节点的渲染。为什么不使用 rAF() 呢?// 1s 执行一次。原创 2024-02-13 19:30:27 · 1772 阅读 · 0 评论 -
React18原理: 再聊Fiber架构下的时间分片
react的任务可以被打断,其实就是基于时间分片的,人眼最高能识别的帧数不超过30帧,电影的帧数差不多是在24,浏览器的帧率一般来说是60帧,也就是每秒60个画面, 平均一个画面大概是16.5毫秒左右,浏览器正常的工作流程是运算渲染,运算,渲染运算渲染,在浏览器里面一个运算,加上一个渲染就是一帧原创 2024-02-11 22:13:35 · 2123 阅读 · 1 评论 -
React18原理: Fiber架构下的单线程CPU调度策略
React 的 Fiber 架构, 它的整个设计思想就是去参考CPU的调度策略CPU现在都是多核多进程的,重点研究的是CPU是单核单线程,它是如何调度的?为什么要去研究单线程的CPU?浏览器中的JS它是单线程的JS 的执行线程和浏览器的渲染GUI 是互斥的渲染和JS的执行都用同一个线程,因为一次只能做一件事情,所以互斥所以,React整个架构的整个调度都是去参考 CPU 的。原创 2024-02-10 17:03:31 · 1674 阅读 · 0 评论 -
React18原理: 渲染与更新时的重点关注事项
react 在渲染过程中要做很多事情,所以不可能直接通过初始元素直接渲染还需要一个东西,就是虚拟节点,暂不涉及React Fiber的概念,将vDom树和Fiber 树统称为虚拟节点有了初始元素后,React 就会根据初始元素和其他可以生成虚拟节点的东西生成虚拟节点React一定是通过虚拟节点来进行渲染的对于首次挂载阶段需要了解React的渲染流程通过书写的初始元素和一些其他可以生成虚拟节点的东西来生成虚拟节点然后针对不同的节点类型去做不同的事情,最终将真实DOM挂载到页面上。原创 2024-02-09 23:02:46 · 1778 阅读 · 0 评论 -
React18原理: 生命周期中特别注意事项
生命周期就是一个组件从诞生到销毁的全过程(包含错误捕获,这里暂且不聊这个)react 在组件的生命周期中注册了一系列的钩子函数支持开发者在其中嵌入代码,并在适当的时机运行生命周期本质上就是组件中的钩子函数,主要有三个主要的钩子挂载更新卸载。原创 2024-02-09 21:10:11 · 1877 阅读 · 0 评论 -
React16源码: React中ReactFiberScheduler的expirationTime及nextExpirationTimeToWorkOn的源码实现
expirationTime 作用在渲染之前的,而 nextExpirationTimeToWorkOn 则是作用在渲染时的。让它在下一次执行更新之前来使用 performSyncWork 这种方式来通过同步的方式去渲染任务。这两个值在整个 render 以及 commit 的过程当中,都起着非常重要的一个作用。所以这就是这两个值它的作用, 通过指定它们来指定更新模式以及更新任务的优先级。为什么说 expirationTime 是作用在渲染前的呢?比如说, 在 renderRoot 中。原创 2024-02-04 12:58:32 · 1101 阅读 · 0 评论 -
React16源码: React中更新阶段中不同类型的expirationTime之pendingTime,suspendedTime以及pingedTime的源码实现
现在发现,3种 expirationTime 的处理最终都调用了。下面是 renderRoot 中的一段代码。2.2 关于 suspendedTime。2.1 关于 pendingTime。原创 2024-02-03 22:05:09 · 831 阅读 · 0 评论 -
React16源码: React中详解在渲染阶段Suspend的源码实现
1 )把优先级放到低优先级的任务上会把当前 render 直接废弃,让低优先级的任务再次去渲染这些更新来查看他是否可以把错误解决掉2 )直接发起一个新的同步更新没有低优先级的任务,会重新发起的是同步更新来强制再次去渲染一次来看是否可以解决这个问题如果不能解决,那么就代表不能解决这个问题,只能按照错误的方式去把内容渲染出来3 )设置timeout然后提交只有在 throw 的是 Promise 的情况。原创 2024-02-03 17:21:31 · 1167 阅读 · 0 评论 -
React16源码: React中event事件中batchedUpdates, controlled inputs以及事件绑定dispatchEvent源码实现
前面把 react 当中事件从开始注入到事件的监听,到把整个事件对象给它构造出来,最后去触发这个事件的整体的流程,还有一些重要的内容,如:batchedUpdates,controlled inputs 如何回调,关于事件绑定dispatchEvent原创 2024-02-03 10:36:00 · 937 阅读 · 0 评论 -
React16源码: React中event事件对象的创建过程源码实现
目前为止,通过 ChangeEventPlugin 来了解了整个 event 对象的处理过程。这一套东西只是非常适合react,在其他框架要使用这类event库,会有很大的成本。react 团队把整个事件系统去重新抽象的这么一个过程,而且设计的超级复杂。以上,生产 event 对象,然后去挂载它的事件,这个过程是非常的复杂的。但每一个 plugin 或多或少有一些自己的一些区别,这里不再赘述。我们专门专注下 changeEvent 的这个方法。后续其他的类似事件的处理逻辑到后面都是一样的。原创 2024-02-03 00:14:10 · 1429 阅读 · 0 评论 -
React16源码: React中event事件触发的源码实现
它是出于对各种系统的一个兼容调用的一个方法来进行一个 Polyfill。,这个 target 就是我们 event 对象上面的 target。我们真正的每一个节点上面,如果有绑定这个事件,它就会调用它的一个回调。这就是事件触发的整个流程, 非常的繁琐,有各种各样的方法,嵌套的调用。到这里为止,这边的 listener 就已经被调用了。batchedUpdates 里面调用的方法是。原创 2024-02-02 20:01:13 · 1589 阅读 · 0 评论 -
React16源码: React中event事件监听绑定的源码实现
在 react-dom 代码初始化的时候,去注入了平台相关的事件插件,接下去在react的更新过程绑定了事件的操作,在执行到 completeWork 的时候,对于 HostComponent 会一开始就先去执行了 finalizeInitialChildren 这个方法原创 2024-02-01 23:52:57 · 1327 阅读 · 0 评论 -
React16源码: React中event事件系统初始化源码实现
把这几个变量维护好之后,后面可以很方便的进行一些事件绑定相关的操作。通过以上操作,插入了所有的plugin之后,形成了这边的几个变量。看到它 import 了一大堆的东西,后续只是调用了3个方法。以上就是把整个事件的插件它注入到react事件系统当中的过程。重点关注最终拿到的几个完成注册之后的变量的数据格式。对于事件注入这个模块,是初始化事件的前置任务。这个模块下的 injection。原创 2024-02-01 21:53:57 · 1557 阅读 · 0 评论 -
React16源码: React中处理hydrate的核心流程源码实现
如果不能找到,就对这节点以及它的子树停止一个 hydrate 的流程,然后设置一些全局变量。在 beginWork 的流程当中,去判断更新的一个 HostComponent。是否可以从 hydrate 的 dom 节点当中去找到一个可以复用的节点。方法标志着整个 react 应用的 hydrate 过程的一个开启。第4个参数 forceHydrate 表示是否强制融合。接下去走的流程是在 completeUnitOfWork。开始了之后要做的是什么呢?原创 2024-01-31 23:29:01 · 1150 阅读 · 0 评论 -
React16源码: React中处理ref的核心流程源码实现
在更新流程当中如何去设置ref上面的对象的过程,在我们创建fiber的时候去处理ref这个属性,那我们什么时候创建fiber对象? 就是我们去更新某一个节点,然后要去调和它的子节点的时候,这个时候我们会对每一个子节点去创建这个fiber对象,创建这个fiber对象的过程,我们就会去处理这个ref,commit开始之前先detach原创 2024-01-31 19:00:00 · 1543 阅读 · 0 评论 -
React16源码: React中NewContext的源码实现
新的 context API 是一个组件化的使用方式, context的提供方和订阅方都是独立的, 没有什么附带的性能影响原创 2024-01-30 23:59:46 · 507 阅读 · 0 评论 -
React16源码: React中LegacyContext的源码实现
对于在 beginWork 中的 context 操作,可以看上述判断成立的条件下的代码,即便有符合跳过更新的操作,依然 需要 push 和 pop 操作。如果我们可以跳出组件的更新,也就是代表着当前这个 classComponent,它的state它的props都应该是没有任何变化的。对于子组件来说,它的所有子树所获取到的context肯定是经过子组件,和上层的父组件合并的 context 了, 也就是。所以,先 push 一个老的值进去再说, 然后到后面,如果发现这个组件它是要更新的,就调用这个。原创 2024-01-29 19:30:00 · 2577 阅读 · 0 评论 -
React16源码: React中context-stack的源码实现
如果在没有理清楚之前的整一个react的更新的过程的时候就来讲这些PI呢可能会让大家很难去理解这部分内容。context内部有一个概念是 stack, 有一个唯一的stack,里面保存各种各样的东西。react是一个非常纯粹的框架, 它的纯粹体现在哪里?所以呢我单独把它放到我们整个核心环节的后面。原创 2024-01-28 22:33:53 · 1169 阅读 · 0 评论 -
React16源码: React中commit阶段的commitAllLifeCycles的源码实现
以上是对所有的具有 SideEffect 的节点在commit过程当中执行任务的一个过程,到这里,整个dom树其实也已经渲染上去了。包括可能存在 autofocus 的处理过程,所以它相当于是在整个应用渲染完成之后的一个善后工作。其实主要是调用不同组件的一个生命周期,以及对于 HostComponent,等组件的不同处理。具体细节,写在上述代码的注释中。原创 2024-01-27 15:44:30 · 1304 阅读 · 0 评论 -
React16源码: React中commitAllHostEffects内部的commitDeletion的源码实现
对于 Portal,ClassComponent,还有 HostComponent,会有不同的操作。对于这个整体流程,用下面的图来看下,比如说,要删除图中 App下的 div 节点。最重要的就是理解这个算法它如何进行递归的调用来遍历整棵子树每一个节点的过程。需要注意的是,对于HostComponent的子树的遍历会放到这个。方法,它遍历的过程的目的是。描述了整个删除的流程。原创 2024-01-26 23:59:18 · 1241 阅读 · 0 评论 -
React16源码: React中commitAllHostEffects内部的commitWork的源码实现
以上就是整个 commitWork 里面做的事情, 具体的细节写在代码注释里。对于 HostText 它也要进行一个更新,它调用了一个。对于 HostComponent 来说。原创 2024-01-26 19:19:49 · 1244 阅读 · 0 评论 -
React16源码: React中commitAllHostEffects内部的commitPlacement的源码实现
在 react commit 阶段的 commitRoot 第二个while循环中,调用了 commitAllHostEffects,在这个函数内部处理了,把一个新的dom节点挂载到真正的dom树上面去的一个过程现在主要关注下其中调用的 commitPlacement原创 2024-01-26 12:58:39 · 1296 阅读 · 0 评论 -
React16源码: React中commit阶段的commitAllHostEffects的源码实现
回到 commit 阶段的第二个循环中,在 commitRoot 函数里。因为每一个 effect 对象上面可能有不同的各种 effectTag。上面是使用的地方,现在定位到 commitAllHostEffects。所以它们都是要再次经历一个循环之后去判断是否要进行对应的操作的。接下去就是赋值 nextEffect,然后再次进入这个循环。所以每一个循环开始之前,都要重新赋值成单项链表的开头。直到我们整个单链表循环完成之后,它就结束了。注意,在执行新的循环之前,都要执行。原创 2024-01-26 01:00:00 · 1646 阅读 · 0 评论 -
React16源码: React中commit阶段的commitBeforeMutationLifecycles的源码实现
在 react commit阶段的 `commitRoot` 第一个while循环中, 调用了 `commitBeforeMutationLifeCycles`, 现在来看下,里面发生了什么原创 2024-01-25 22:30:00 · 1009 阅读 · 0 评论 -
React16源码: React中commit阶段的invokeGuardedCallback的源码实现
在 commit 阶段中在 DEV 环境中调用了 `invokeGuardedCallback` 这个方法, 这个方法是在开发过程中被使用,用于捕获错误,协助开发调试的方法原创 2024-01-25 21:45:00 · 1092 阅读 · 0 评论 -
React16源码: React中commit阶段的commitRoot的主流程源码实现
以上就是整个 commitRoot的一个流程, 细节都写在代码注释中了。这个流程当中,这三个循环看起来这么复杂,那么其实它并不复杂。后续会看下这里的细节实现。原创 2024-01-25 19:45:00 · 974 阅读 · 0 评论 -
React16源码: React中的unwindWork的源码实现
在 renderRoot 的 throw Exception 里面, 对于被捕获到错误的组件进行了一些处理并且向上去寻找能够处理这些异常的组件,比如说 class component 里面具有getDerivedStateFromError 或者 componentDidCatch 这样的生命周期方法这个class component 就代表它可以处理它的子树当中渲染出来的任何的错误原创 2024-01-24 19:53:13 · 1576 阅读 · 0 评论 -
React16源码: React中的renderRoot的错误处理的源码实现
经过以上的处理,在调用了所有 exception 之后,最后 立马调用了。这就说明这个节点报错了,这个节点已经完成了,它不会再继续去渲染它的子节点了。它走的就是 unwindWork 的流程了, 这个后续来看。因为这个节点它已经出错了,再渲染它的子节点是没有任何意义。所以在这里面,如果有一个节点,出错了,就会立马对它执行。里面的 do while 循环中。这个是常规处理错误的处理器。原创 2024-01-24 12:23:37 · 1397 阅读 · 0 评论