React16源码: React中的unwindWork的源码实现

前端开发高级进阶深入讲解React源码 目录 ├─视频 │├─01-01 课程导.mp4 │├─02-01 准备工作.mp4 │├─02-02 JSX到JavaScript的转换.mp4 │├─02-03 react-element.mp4 │├─02-04 react-component.mp4 │├─02-05 react-ref.mp4 │├─02-06 forward-ref.mp4 │├─02-... 阅读详情

unwindWork


1 )概述

  • 在 renderRoot 的 throw Exception 里面, 对于被捕获到错误的组件进行了一些处理
  • 并且向上去寻找能够处理这些异常的组件,比如说 class component 里面具有
  • getDerivedStateFromError 或者 componentDidCatch 这样的生命周期方法
  • 这个class component 就代表它可以处理它的子树当中渲染出来的任何的错误
  • 但是在这个过程当中,只是在上面增加了一些 SideEffect
    • 比如说, 在出错的那个组件上,增加了 Incomplete
    • 而对于能够处理这个错误的组件,增加了 ShouldCapture
  • 这些 SideEffect 最终会被如何进行处理, 这时候就要用到 unwindWork 了
  • 类似于 completeWork,对于不同组件, 进行一些不同的处理
    • 它整个流程是跟 completeWork 完全区分开的
    • 它当然也要去做一些 completWork 里面会做的一些工作
    • 但是它们肯定会有一些区别,不然它们也不需要进行一个区分
  • 对于 ShouldCapture 组件会设置 DidCapture 副作用

2 )源码

定位到 packages/react-reconciler/src/ReactFiberScheduler.js#L1354

定位到 throwException

throwException(
  root,
  returnFiber,
  sourceFiber, // 报错的那个组件
  thrownValue,
  nextRenderExpirationTime,
);
nextUnitOfWork = completeUnitOfWork(sourceFiber);
continue;
  • 进入 throwException 下面是精简版,只看结构

    function throwException(
      root: FiberRoot,
      returnFiber: Fiber,
      sourceFiber: Fiber,
      value: mixed,
      renderExpirationTime: ExpirationTime,
    ) {
      // 添加 Incomplete
      // The source fiber did not complete.
      sourceFiber.effectTag |= Incomplete;
      // Its effect list is no longer valid.
      // 清空 Effect 链
      sourceFiber.firstEffect = sourceFiber.lastEffect = null;
      // ... 其他代码忽略
    
  • 进入 completeUnitOfWork 下面是精简版,只看结构

    function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
      while (true) {
        // ... 跳过很多代码
        // 符合这个条件,走的是 completeWork
        if ((workInProgress.effectTag & Incomplete) === NoEffect) {
          // This fiber completed.
          if (enableProfilerTimer) {
            // ... 跳过很多代码
            nextUnitOfWork = completeWork(
              current,
              workInProgress,
              nextRenderExpirationTime,
            );
            // ... 跳过很多代码
          } else {
            nextUnitOfWork = completeWork(
              current,
              workInProgress,
              nextRenderExpirationTime,
            );
          }
          // ... 跳过很多代码
        } else {
          // ... 跳过很多代码
    
          // 否则,走的是 unwindWork, 对于不同的组件,这个返回值也会不同
          const next = unwindWork(workInProgress, nextRenderExpirationTime);
          
          // ... 跳过很多代码
          if (next !== null) {
            // ... 跳过很多代码
            next.effectTag &= HostEffectMask; // 注意这个运算,只有在 当前effect和HostEffectMask共有的,才会最终留存下来
            return next; // 看到这边 return 了 next
          }
          if (returnFiber !== null) {
            // Mark the parent fiber as incomplete and clear its effect list.
            returnFiber.firstEffect = returnFiber.lastEffect = null;
            returnFiber.effectTag |= Incomplete;
          }
        }
      }
      return null;
    }
    
    • 在 next.effectTag &= HostEffectMask 这个运算中,这边可能会有一个问题
    • Incomplete 是在 sourceFiber 上面,也就是说报错的那个组件上面的
    • 但是它向上寻找的就是能够处理错误的组件, 它增加的是 ShouldCapture
    • 需要注意的一点是,一开始进来处理的第一个组件,它是报错的那个组件,它并不一定是能够处理错误的那个组件
    • 因为在 unwindWork 里面,增加这个 ShouldCapture 的时候
    • 是我们在一个循环中向报错的那个组件的父链上面去寻找,可以处理错误的那个组件
    • 一般它是 HostRoot 或者是 ClassComponent
    • 所以一进来的时候处理的组件是报错那个组件,它可能不是一个ClassComponent,或者它没有错误处理的能力
    • 这个时候它不一定会进来这个 next !== null 的这个判断,那么它会往下走
    • 那往下走的时候,它判断了returnfivever不等于诺的情况
    • 它会去给 returnFiber 增加这个 Incomplete 的 effectTag
    • 也就是说如果一个子树当中的组件报错了,对于它父链上的所有组件的 completeUnitOfWork
    • 都会执行对应的 unwindWork 的流程,而不会走 completeWork的流程
    • 进入 unwindWork
      function unwindWork(
        workInProgress: Fiber,
        renderExpirationTime: ExpirationTime,
      ) {
        switch (workInProgress.tag) {
          // 在这里面,它根据不同的组件类型处理了这些内容
          // 它主要处理的就是 ClassComponent, HostComponent SuspenseComponent 
          // 剩下的一些基本上都是跟 completeWork 里面类似
          // 对于这些组件,它跟 completeWork 最大的区别就是它会去判断 ShouldCapture 这个 SideEffect
          // 如果我们这个组件上面有 ShouldCapture 这个 SideEffect
          // 那么它会把 ShouldCapture 给它去掉, 然后增加这 DidCapture 这个 SideEffect
          // 这就是对于 classComponent 跟 completeWork 里面的一个最主要的区别
          case ClassComponent: {
            const Component = workInProgress.type;
            if (isLegacyContextProvider(Component)) {
              popLegacyContext(workInProgress);
            }
            const effectTag = workInProgress.effectTag;
            if (effectTag & ShouldCapture) {
              // 注意这里
              workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture;
              return workInProgress;
            }
            return null;
          }
          // 与 ClassComponent 类似
          case HostRoot: {
            popHostContainer(workInProgress);
            popTopLevelLegacyContextObject(workInProgress);
            const effectTag = workInProgress.effectTag;
            invariant(
              (effectTag & DidCapture) === NoEffect,
              'The root failed to unmount after an error. This is likely a bug in ' +
                'React. Please file an issue.',
            );
            // 注意这里
            workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture;
            return workInProgress;
          }
          case HostComponent: {
            popHostContext(workInProgress);
            return null;
          }
          case SuspenseComponent: {
            const effectTag = workInProgress.effectTag;
            if (effectTag & ShouldCapture) {
              workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture;
              // Captured a suspense effect. Set the boundary's `alreadyCaptured`
              // state to true so we know to render the fallback.
              const current = workInProgress.alternate;
              const currentState: SuspenseState | null =
                current !== null ? current.memoizedState : null;
              let nextState: SuspenseState | null = workInProgress.memoizedState;
              if (nextState === null) {
                // No existing state. Create a new object.
                nextState = {
                  alreadyCaptured: true,
                  didTimeout: false,
                  timedOutAt: NoWork,
                };
              } else if (currentState === nextState) {
                // There is an existing state but it's the same as the current tree's.
                // Clone the object.
                nextState = {
                  alreadyCaptured: true,
                  didTimeout: nextState.didTimeout,
                  timedOutAt: nextState.timedOutAt,
                };
              } else {
                // Already have a clone, so it's safe to mutate.
                nextState.alreadyCaptured = true;
              }
              workInProgress.memoizedState = nextState;
              // Re-render the boundary.
              return workInProgress;
            }
            return null;
          }
          case HostPortal:
            popHostContainer(workInProgress);
            return null;
          case ContextProvider:
            popProvider(workInProgress);
            return null;
          default:
            return null;
        }
      }
      
      • 注意,ClassComponent和HostRoot的return内容
      • 对于HostRoot来说,所有情况下都 return workInProgress
      • 而对于 ClassComponent 在有 ShouldCapture 的时候,return的是当前 workInProgress, 否则是return null
  • 还是拿出之前的图来说这个整体流程

  • 比如说,上面这张图里面 List 这个组件它渲染的时候报错了
  • 但是它没有 getDerivedStateFromError 或者 componentDidCatch 这样的生命周期方法
  • 那么它是不会增加 ShouldCapture 这个 SideEffect 的
  • 如果这个时候,App组件具有 getDerivedStateFromError 或者 componentDidCatch
  • 这个时候 App 增加的是 ShouldCapture 这个 SideEffect
  • 在 throw Exception 处理完之后,要执行的 completeUnitOfWork 第一个节点是 List 这个组件
    • 也就是说它执行的时候,它里面的 next 是 null,会继续往下面的 returnFiber 判断中去
    • 得到的 returnFiber 是 div, 对 div 增加了这些 SideEffect 之后
  • 它又会走 completeUnitOfWork 之后,仍然走的是 unwindWork
  • 这时的 div 是一个 HostComponent,它不会处理错误,然后又走到下一个
  • 走到 App,到 unwindWork 之后,发现它是有 ShouldCapture 这个 SideEffect 的
  • 它 return 的是 workInProgress,之后有next了,这边就可以 return next
  • 并且它上面会具有 DidCapture 的 SideEffect
  • 它 return next 之后,对于 completeUnitOfWork 相当于是return了一个Fiber对象
  • 也就是说 renderRoot 处理异常后面 completeUnitOfWork 返回的 nextUnitOfWork 对象
  • 就变成了App组件它对应的Fiber对象,也就是说,nextUnitOfWork 现在等于App
  • 我们的 do while 循环仍然要继续,依然继续调用 workLoop
  • 调用 workLoop 就会调用 performUnitOfWork,然后调用 beginWork
  • 所以对于 App 这个组件,又需要去重新走一遍更新的流程
  • 但是走更新的流程的时候,这个时候已经不一样了,不一样在哪里呢?
    • App它是一个 ClassComponent,所以我们要走的是 updateClassComponent
    • 在 ReactFiberBeginWork.js 中,找到 updateClassComponent
    • 这边正常走下来,其实都是差不多的,创建这些流程之类的
    • 这边需要注意的是,比如说 updateClassInstance
    • 它对应的是在 ReactFiberClassComponent.js 里面,找到这个方法
    • 在这个方法里面,它会去 processUpdateQueue
    • 在按 unwindWork的时候,给ClassComponent 创建了一个update 叫 createClassErrorUpdate
    • 这个 update 它会去调用 getDerivedStateFromError,以及它会有一个callback是调用 componentDidCatch
    • 所以如果有 getDerivedStateFromError 这个方法,对应的在 ClassComponent 里面
    • 在进行 processUpdateQueue 的时候,肯定会调用这个方法
    • 它就会计算出有错误的情况下它的一个state
    • 这个state就会引导 ClassComponent 去渲染错误相关的UI
    • 这就是我们的组件 ClassComponent 去捕获错误,并且去渲染出错误相关UI的一个流程
    • 因为渲染的是错误相关的UI, 所以原先的它的子树肯定是不会再被渲染出来的
    • 或者有可能会被渲染出来, 这个情况视具体的内容而定
  • 在这种情况下,再回到 beginWork,再往下调用 finishClassComponent 的时候
  • 有一个判断是 if ( didCaptureError && typeof Component.getDerivedStateFromError !== 'function') {}
    • didCaptureError 来自于我们这个组件上面是否有 DidCapture 这个 SideEffect
    • 在有错误的情况下,它这个属性肯定是 true
    • 并且没有 getDerivedStateFromError 的情况,先不管,继续往下看
  • 下面的一个判断 if (current !== null && didCaptureError) {}
    • 它会执行的一个方法是 forceUnmountCurrentAndReconcile
    • 这个情况就是最常见的一个情况,就是组件是在一个更新的过程当中
    • 然后它的子树出现了错误,这个App要去渲染错误,它这边的 didCaptureError 就是 true
      function forceUnmountCurrentAndReconcile(
        current: Fiber,
        workInProgress: Fiber,
        nextChildren: any,
        renderExpirationTime: ExpirationTime,
      ) {
        // This function is fork of reconcileChildren. It's used in cases where we
        // want to reconcile without matching against the existing set. This has the
        // effect of all current children being unmounted; even if the type and key
        // are the same, the old child is unmounted and a new child is created.
        //
        // To do this, we're going to go through the reconcile algorithm twice. In
        // the first pass, we schedule a deletion for all the current children by
        // passing null.
        workInProgress.child = reconcileChildFibers(
          workInProgress,
          current.child,
          null,
          renderExpirationTime,
        );
        // In the second pass, we mount the new children. The trick here is that we
        // pass null in place of where we usually pass the current child set. This has
        // the effect of remounting all children regardless of whether their their
        // identity matches.
        workInProgress.child = reconcileChildFibers(
          workInProgress,
          null,
          nextChildren,
          renderExpirationTime,
        );
      }
      
      • 1 )它先调用了一遍 reconcileChildFibers, 先看下它的构造结构
         function reconcileChildFibers(
           returnFiber: Fiber,
           currentFirstChild: Fiber | null,
           newChild: any,
           expirationTime: ExpirationTime,
         ): Fiber | null {}
         ```
        
        * 这边需要注意的是, 它传入的 newChild 是 null
        * 就是说它要强制把目前所有的子树的节点全部给它删掉
        * 它渲染出没有子树的 ClassComponent
        
      • 2 )然后再渲染一遍
        • 这个时候传入的 currentFirstChild (老的 children) 是 null
        • 然后传入的 newChild 是 nextChildren
          • 因为这个 nextchildren 是我们已经从新的(有错误的)update里面, 计算出的一个新的 state
          • 这个children, 一般来说,它跟老的 children 是完全不一样的
          • 就算不是完全不一样,也可能是大部分不一样
          • 它强制在第一次的时候直接用 null, 把它的子树给清空,然后渲染新的 children
        • 这样的效率会更高一点,就不需要通过key去对比这些流程了
  • 这就是在react 它的 error boundary 这个功能
    • 提供我们 ClassComponent , 使用 getDerivedStateFromError 或者 componentDidCatch
    • 这样的生命周期方法来处理,捕获到错误之后的一个流程
  • 同样的, 这是 unwindWork 处理流程当中需要注意的一些点
日前日内多阶段多时间尺度源荷储协调调度(matlab代码) 多阶段多时间尺度的协调调度的优势是考虑新能源出力的波 动性与随机性,需求响应负荷的不确定性会对电网制定的日前调度计划准确性造成影响,也就是能够更加精准的进行调度和分析,优化结果的可用性更强。在这方面论文里面,金力的《考虑特性分布的储能电站接入的电网多时间尺度源储荷协调调度策略》就考虑了日前日内实时三个阶段调度,每个阶段考虑了不同负荷需求响应策略,同时考虑了负荷波动性的影响,具有很强的参考意义。 目录 一、模型 二、程序运行 三、程序链接 一、模型 负荷需求响应考虑电价型和激励型两种,电. 阅读详情

相关推荐

FFmpeg魔改指南:让RTMP协议完美兼容H265的三种方法(含SRS适配技巧)

本文详细介绍了三种让RTMP协议兼容H265编码的FFmpeg魔改方案,包括基于官方补丁的标准改造、Intel的SVT-HEVC集成方案以及金山云的自定义扩展方案。文章重点解析了各方案的实现原理与适配技巧,并提供了在SRS 6.0服务器上进行深度配置和性能调优的完整实战指南,帮助开发者解决H265推流至传统RTMP服务器的兼容性问题。

weixin_29290947的博客 197

react源码分析(11)-错误边界机制

目录 谈谈错误边界的概念 找到待处理节点 找到错误边界 总结 2021SC@SDUSC 谈谈错误边界的概念 在部分UI内部的JavaScript中可能捕获到异常,为了确保整个应用能够顺利运行,可以在组件树中找到发生异常的组件,利用错误边界组件捕获并打印组件中的错误,并且展示备用UI,不会继续渲染那些已经发生崩溃的子组件树,错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。为明晰相关概念,根据官方文档,这里给出不被错误边界所处理的种种情况:事件处理,异步代码(例如setTi...

weixin_45668912的博客 815

Vivado 18.3安装全攻略:从下载到配置的完整指南

本文详细介绍了Vivado 18.3的安装全流程,从下载准备到配置优化,特别适合FPGA开发者。文章包含硬件要求、版本选择、组件配置等实用技巧,帮助用户避免常见安装问题,确保稳定运行。重点解析了License配置和系统优化设置,提升开发效率。

weixin_28331555的博客 568

Fix signatures do not match the previously installed version

报错信息FAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:installDebug'. > com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: Fai

Wang的专栏 2万+

Tip-Adapter: Training-free Adaption of CLIP for Few-shot Classification

对比式视觉-语言预训练,也称为CLIP,通过大规模的图像-文本对来学习视觉表示,为zero-shot知识迁移展示了新的范式。它在下游任务上展现出令人瞩目的性能,实现了zeri-shot的知识迁移。为了进一步增强CLIP的适应能力,现有方法提出了微调可学习模块的方法,显著提高了少样本情况下的性能,但也引入了额外的训练时间和计算资源。在本文中,我们提出了一种适用于CLIP的无需训练的少样本分类方法,称为Tip-Adapter。

qq_43800752的博客 1165

R_柱状图(加误差线,显著性差异)

先放最终效果图 结果图 # bar_plot 2021/01/19 # 导入所需的包 library(ggplot2) library(ggthemr) library(ggsignif) library(tidyverse) library(dplyr) library(ggpubr) library(devEMF) # 导入并处理数据,需要两张表,一个是原始汇总表格,另外一些是每一...

wt141643的博客 2万+

在react中 实现 base64的图片转换成formdata格式并实现上传功能

如果不想要服务端实现处理base64格式的图片的转换,那么在浏览器端来实现,部分属于伪代码,仅作为开发参考,请勿直接拷贝使用

Wang的专栏 8836

从命令到对话:LLM如何重塑车载语音交互与软件定义汽车体验

自动语音识别和自然语言处理是智能交互的核心基础技术,它们使机器能够理解和响应人类语音指令。其原理在于通过声学模型和语言模型将声音信号转化为文本,再解析文本背后的用户意图。这项技术的价值在于提供了一种自然、高效且能解放双手的人机交互方式,极大地提升了在特定场景(如驾驶)下的安全性与便利性。随着技术演进,其应用场景已从简单的命令控制扩展到复杂的多轮对话和跨域任务执行。当前,软件定义汽车的架构变革为车载语音提供了统一的控制平台,而大型语言模型的引入则带来了范式革命,使其从功能触发器进化为真正的智能任务执行者。本文

weixin_42669344的博客 564

快速解决gradle下载慢的问题的小技巧

在ionic run 或build 或clean命令的时候,如果没有下载过gradle, 需要重新下载一次,而通过CLI的方式下载很慢,即使科学上网后,下载还是存在一些问题。这里总结一下,快速的下载安装方式。 步骤 本地安装 http-server 包, 通过 $ npm i -g http-server 的方式安装到全局 在官网上下载自己的版本,目前自带的版本是 2.14.1,其他版本可能在执行过

Wang的专栏 6714

YOLOv11 改进 | 模块即插即用

YOLOv11 是一种单阶段目标检测算法,其核心设计目标在于实现检测速度与精度的平衡。其架构延续了 YOLO 系列“端到端”检测的思路,通过统一的网络结构完成特征提取、多尺度特征融合及最终的边界框预测与分类任务。骨干网络(Backbone)颈部网络(Neck)和检测头(Head)。骨干网络负责从输入图像中提取多层次的语义特征。

u012133341的博客 3123

Linux ARM平台开发系列讲解(调试篇) 1.6.4 NVIDIA AGX Xavier以太网MAC TO MAC模式

内核发展了那么多年,早已经将这种场景集成到了内核里,具体添加方式如下,本次针对。具体详细描述,可参考本专栏的网络篇和交换机篇,这里就简单的提一句,想要使用。速率和双工状态固定死,使其和交换机的模式一模一样,双方就可以建立通信了。2. MAC TO MAC原理。3. 开启无PHY模式进入内核。模式,本章节记录调试过程。模式,简单来说就是字面意思,以太网部分需要与交换机。,其他芯片也是一样的。修改设备树文件,将与。

DSMGUOGUO的博客 1531

React 实现 2D 画板功能

在移动端或者PC端我们来模拟画板的实现, 支持清除和导出功能,此处简单实现,仅作开发参考。 效果演示 主要代码演示 /* 此模块用于实现签名绘图功能 */ // 需要用到的变量定义 let clickX = new Array(); let clickY = new Array(); let clickDrag = new Array(); let paint; let point...

Wang的专栏 4325

【数据集】米级别热红外卫星合集:SDGSAT-1、HotSat-1等

米级别热红外卫星合集:SDGSAT-1、HotSat-1等

WW、forever的博客 1259

React16源码: React中LegacyContext的源码实现

对于在 beginWork 中的 context 操作,可以看上述判断成立的条件下的代码,即便有符合跳过更新的操作,依然 需要 push 和 pop 操作。如果我们可以跳出组件的更新,也就是代表着当前这个 classComponent,它的state它的props都应该是没有任何变化的。对于子组件来说,它的所有子树所获取到的context肯定是经过子组件,和上层的父组件合并的 context 了, 也就是。所以,先 push 一个老的值进去再说, 然后到后面,如果发现这个组件它是要更新的,就调用这个。

Wang的专栏 2803

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Fix babel-preset-react-native TransformError

错误环境新版本存在不兼容,在运行 react-native run-android 的时候,发生的错误分析: babel-preset-react-native version : @3.0.0 $ react-native -v :react-native-cli: 2.0.1 react-native: 0.47.1$node -v : v7.8.0 $ npm -v :4.4.4 解决方案

Wang的专栏 2800

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

React18原理: 再聊Fiber架构下的时间分片

react的任务可以被打断,其实就是基于时间分片的,人眼最高能识别的帧数不超过30帧,电影的帧数差不多是在24,浏览器的帧率一般来说是60帧,也就是每秒60个画面, 平均一个画面大概是16.5毫秒左右,浏览器正常的工作流程是运算渲染,运算,渲染运算渲染,在浏览器里面一个运算,加上一个渲染就是一帧

Wang的专栏 2796

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

在react项目中修改webpack中本地服务器架设的目录

一个产品的上线往往会有很多的问题,现在就出现一个需求,我们是在服务器下的某个目录进行发布,而不是根服务器,服务端不想为一个项目配置ip地址,而在react项目中,默认是走的根路径,现在我们就开始修改一下它。 前提说明 如果我们需要修改手动配置webpack, 那么根据现在的版本, 我们只能执行 npm run eject, 之后就可以着手修改了。 webpack中与需求相关的...

Wang的专栏 2397

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的代表的数值越小,此次更新的优先级就越大。

Wang的专栏 2394

React18原理: 核心包结构与两大工作循环

react中的工作循环,这是它的一个最顶层的一个流程图,在这张图里面,有两个核心的大循环,第一大循环是 react-reconciler 提供的,它的核心是构建fiber树,生成任务,第二大循环是 scheduler 提供的, 它的核心是任务调度(处理任务的优先级),react的原理实际上就是两大工作循环

Wang的专栏 2356

React18原理: 生命周期中特别注意事项

生命周期就是一个组件从诞生到销毁的全过程(包含错误捕获,这里暂且不聊这个)react 在组件的生命周期中注册了一系列的钩子函数支持开发者在其中嵌入代码,并在适当的时机运行生命周期本质上就是组件中的钩子函数,主要有三个主要的钩子挂载更新卸载。

Wang的专栏 2244

React16源码: React中的beginWork的源码实现

定位到 packages/react-reconciler/src/ReactFiberBeginWork.js。整个文件 export 出去的只有 beginWork 方法。

Wang的专栏 2140

React16源码: React中的reconcileChildren的源码实现

在更新了一个节点之后,拿到它的props.children, 要根据这个children里面的 ReactElement 来去创建子树的所有的 fiber 对象, 要根据 props.children 来生成 fiber 子树,然后判断 fiber 对象它是否是可以复用的

Wang的专栏 2133

React16源码: React中的completeUnitOfWork的源码实现

各种不同类型组件的一个更新过程对应的是在执行 `performUnitOfWork` 里面 `beginWork` 阶段,它是去向下遍历一棵 fiber 树的一侧的子节点,然后遍历到叶子节点为止,以及 return 自己 child 的这种方式

Wang的专栏 2088

React18原理: 渲染与更新时的重点关注事项

react 在渲染过程中要做很多事情,所以不可能直接通过初始元素直接渲染还需要一个东西,就是虚拟节点,暂不涉及React Fiber的概念,将vDom树和Fiber 树统称为虚拟节点有了初始元素后,React 就会根据初始元素和其他可以生成虚拟节点的东西生成虚拟节点React一定是通过虚拟节点来进行渲染的对于首次挂载阶段需要了解React的渲染流程通过书写的初始元素和一些其他可以生成虚拟节点的东西来生成虚拟节点然后针对不同的节点类型去做不同的事情,最终将真实DOM挂载到页面上。

Wang的专栏 2069

21st.dev 上手教程:12000+ React 组件库怎么用,6 步从挑样式到接进 Cursor

21st.dev 收录 12000+ 个 React + Tailwind 组件、297 套整站模板与 979 套主题。本文是手把手流程版:按页面用途找组件、用复制或 shadcn CLI 落地、接入 MCP 让 Cursor 自己取代码、用整站模板开局,附 10 张真实组件截图和 4 个常见坑。

懿轩的技术小窝 232

手搓 AI Agent 02:让模型第一次“动手“——Agent Loop 与 ReAct

本系列第2篇实现Agent核心循环——ReAct模式,让模型从“被动回答”变为“主动执行”。通过LLMClient工具调用能力,构建think → act → observe闭环,首次实现模型自主调用计算器、读取结果并继续推理。代码支持安全算术、步数限制与错误隔离,升级终端REPL为可观察的智能体交互界面。每步操作清晰可见,为后续多工具、规划与协作打下基础。

快乐来自程序里 130
上一篇: React16源码: React中的renderRoot的错误处理的源码实现
下一篇: React16源码: React中commit阶段的commitRoot的主流程源码实现
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值