React16源码: React中commit阶段的invokeGuardedCallback的源码实现

React源码分析(二)=> Reac初次渲染分析 Reac初次渲染分析 源码基于React 16.8.6, 内容极长, 必须配合源码一起来看 单步调试的例子: `ReactDOM.render('hello', document.getElementById('root'))`; 下文基于这个例子来一步一步分析. 阅读详情

invokeGuardedCallback


1 )概述

  • 在 commit 阶段中在 DEV 环境中调用了 invokeGuardedCallback 这个方法
  • 这个方法是在开发过程中被使用,用于捕获错误,协助开发调试的方法

2 )概述

定位到 packages/shared/ReactErrorUtils.js#L41

进入 invokeGuardedCallback

const reporter = {
  onError(error: mixed) {
    hasError = true;
    caughtError = error;
  },
};

/**
 * Call a function while guarding against errors that happens within it.
 * Returns an error if it throws, otherwise null.
 *
 * In production, this is implemented using a try-catch. The reason we don't
 * use a try-catch directly is so that we can swap out a different
 * implementation in DEV mode.
 *
 * @param {String} name of the guard to use for logging or debugging
 * @param {Function} func The function to invoke
 * @param {*} context The context to use when calling the function
 * @param {...*} args Arguments for function
 */
export function invokeGuardedCallback<A, B, C, D, E, F, Context>(
  name: string | null,
  func: (a: A, b: B, c: C, d: D, e: E, f: F) => mixed,
  context: Context,
  a: A,
  b: B,
  c: C,
  d: D,
  e: E,
  f: F,
): void {
  hasError = false;
  caughtError = null;
  invokeGuardedCallbackImpl.apply(reporter, arguments);
}
  • 这个方法它实际调用了 invokeGuardedCallbackImpl.apply(reporter, arguments);
  • 这个 reporter,是定义的一个全局对象
  • 内部初始化了两个变量 hasError 和 caughtError
  • 看下 invokeGuardedCallbackImpl
    // https://github.com/facebook/react/blob/v16.6.3/packages/shared/invokeGuardedCallbackImpl.js
    let invokeGuardedCallbackImpl = function<A, B, C, D, E, F, Context>(
      name: string | null,
      func: (a: A, b: B, c: C, d: D, e: E, f: F) => mixed,
      context: Context,
      a: A,
      b: B,
      c: C,
      d: D,
      e: E,
      f: F,
    ) {
      const funcArgs = Array.prototype.slice.call(arguments, 3);
      try {
        func.apply(context, funcArgs);
      } catch (error) {
        this.onError(error);
      }
    };
    
    if (__DEV__) {
      // In DEV mode, we swap out invokeGuardedCallback for a special version
      // that plays more nicely with the browser's DevTools. The idea is to preserve
      // "Pause on exceptions" behavior. Because React wraps all user-provided
      // functions in invokeGuardedCallback, and the production version of
      // invokeGuardedCallback uses a try-catch, all user exceptions are treated
      // like caught exceptions, and the DevTools won't pause unless the developer
      // takes the extra step of enabling pause on caught exceptions. This is
      // untintuitive, though, because even though React has caught the error, from
      // the developer's perspective, the error is uncaught.
      //
      // To preserve the expected "Pause on exceptions" behavior, we don't use a
      // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake
      // DOM node, and call the user-provided callback from inside an event handler
      // for that fake event. If the callback throws, the error is "captured" using
      // a global event handler. But because the error happens in a different
      // event loop context, it does not interrupt the normal program flow.
      // Effectively, this gives us try-catch behavior without actually using
      // try-catch. Neat!
    
      // Check that the browser supports the APIs we need to implement our special
      // DEV version of invokeGuardedCallback
      if (
        typeof window !== 'undefined' &&
        typeof window.dispatchEvent === 'function' &&
        typeof document !== 'undefined' &&
        typeof document.createEvent === 'function'
      ) {
        const fakeNode = document.createElement('react');
    
        const invokeGuardedCallbackDev = function<A, B, C, D, E, F, Context>(
          name: string | null,
          func: (a: A, b: B, c: C, d: D, e: E, f: F) => mixed,
          context: Context,
          a: A,
          b: B,
          c: C,
          d: D,
          e: E,
          f: F,
        ) {
          // If document doesn't exist we know for sure we will crash in this method
          // when we call document.createEvent(). However this can cause confusing
          // errors: https://github.com/facebookincubator/create-react-app/issues/3482
          // So we preemptively throw with a better message instead.
          // 首先会有一大串长的提醒,说明当前这个环境是不支持的
          invariant(
            typeof document !== 'undefined',
            'The `document` global was defined when React was initialized, but is not ' +
              'defined anymore. This can happen in a test environment if a component ' +
              'schedules an update from an asynchronous callback, but the test has already ' +
              'finished running. To solve this, you can either unmount the component at ' +
              'the end of your test (and ensure that any asynchronous operations get ' +
              'canceled in `componentWillUnmount`), or you can change the test itself ' +
              'to be asynchronous.',
          );
          // 它创建了一个 event 对象
          const evt = document.createEvent('Event');
    
          // Keeps track of whether the user-provided callback threw an error. We
          // set this to true at the beginning, then set it to false right after
          // calling the function. If the function errors, `didError` will never be
          // set to false. This strategy works even if the browser is flaky and
          // fails to call our global error handler, because it doesn't rely on
          // the error event at all.
          // 声明了 didError 为true
          let didError = true;
    
          // Keeps track of the value of window.event so that we can reset it
          // during the callback to let user code access window.event in the
          // browsers that support it.
          let windowEvent = window.event;
    
          // Keeps track of the descriptor of window.event to restore it after event
          // dispatching: https://github.com/facebook/react/issues/13688
          // 来获取 window.event 的对象描述符
          const windowEventDescriptor = Object.getOwnPropertyDescriptor(
            window,
            'event',
          );
    
          // Create an event handler for our fake event. We will synchronously
          // dispatch our fake event using `dispatchEvent`. Inside the handler, we
          // call the user-provided callback.
          // 把前面3个参数给它拿出来,剩下的都是作为它的arguments
          const funcArgs = Array.prototype.slice.call(arguments, 3);
          // 它声明了一个叫做callcallback的一个方法。
          function callCallback() {
            // We immediately remove the callback from event listeners so that
            // nested `invokeGuardedCallback` calls do not clash. Otherwise, a
            // nested call would trigger the fake event handlers of any call higher
            // in the stack.
            fakeNode.removeEventListener(evtType, callCallback, false); // 移除事件监听
    
            // We check for window.hasOwnProperty('event') to prevent the
            // window.event assignment in both IE <= 10 as they throw an error
            // "Member not found" in strict mode, and in Firefox which does not
            // support window.event.
            // 对 window.event 进行兼容处理
            if (
              typeof window.event !== 'undefined' &&
              window.hasOwnProperty('event')
            ) {
              window.event = windowEvent;
            }
    
            // 使用 context 调用 func 传入 funcArgs 后续的参数
            // 注意,在 dev 时,这个 context 可能是 null, 可以向上追溯
            func.apply(context, funcArgs);
            didError = false;
          }
    
          // Create a global error event handler. We use this to capture the value
          // that was thrown. It's possible that this error handler will fire more
          // than once; for example, if non-React code also calls `dispatchEvent`
          // and a handler for that event throws. We should be resilient to most of
          // those cases. Even if our error event handler fires more than once, the
          // last error event is always used. If the callback actually does error,
          // we know that the last error event is the correct one, because it's not
          // possible for anything else to have happened in between our callback
          // erroring and the code that follows the `dispatchEvent` call below. If
          // the callback doesn't error, but the error event was fired, we know to
          // ignore it because `didError` will be false, as described above.
          // 声明一堆和 error 相关的变量
          let error;
          // Use this to track whether the error event is ever called.
          let didSetError = false;
          let isCrossOriginError = false;
    
          function handleWindowError(event) {
            error = event.error;
            didSetError = true;
            // 这种情况下是 跨域错误
            if (error === null && event.colno === 0 && event.lineno === 0) {
              isCrossOriginError = true;
            }
            // 别的地方,有去处理 window.onerror,这里被阻塞了
            if (event.defaultPrevented) {
              // Some other error handler has prevented default.
              // Browsers silence the error report if this happens.
              // We'll remember this to later decide whether to log it or not.
              if (error != null && typeof error === 'object') {
                try {
                  error._suppressLogging = true; // 设置当前标识
                } catch (inner) {
                  // Ignore.
                }
              }
            }
          }
    
          // Create a fake event type.
          const evtType = `react-${name ? name : 'invokeguardedcallback'}`;
    
          // Attach our event handlers
          // 注册两个事件
          window.addEventListener('error', handleWindowError);
          fakeNode.addEventListener(evtType, callCallback, false);
    
          // Synchronously dispatch our fake event. If the user-provided function
          // errors, it will trigger our global error handler.
          // 初始化事件,并立即触发 dispatchEvent
          evt.initEvent(evtType, false, false);
          fakeNode.dispatchEvent(evt); // 触发完,会立即调用 callback
    
          if (windowEventDescriptor) {
            Object.defineProperty(window, 'event', windowEventDescriptor);
          }
    
          if (didError) {
            // 出错了,但是 handleWindowError 没有被调用的处理
            if (!didSetError) {
              // The callback errored, but the error event never fired.
              error = new Error(
                'An error was thrown inside one of your components, but React ' +
                  "doesn't know what it was. This is likely due to browser " +
                  'flakiness. React does its best to preserve the "Pause on ' +
                  'exceptions" behavior of the DevTools, which requires some ' +
                  "DEV-mode only tricks. It's possible that these don't work in " +
                  'your browser. Try triggering the error in production mode, ' +
                  'or switching to a modern browser. If you suspect that this is ' +
                  'actually an issue with React, please file an issue.',
              );
            } else if (isCrossOriginError) {
              error = new Error(
                "A cross-origin error was thrown. React doesn't have access to " +
                  'the actual error object in development. ' +
                  'See https://fb.me/react-crossorigin-error for more information.',
              );
            }
            this.onError(error);
          }
    
          // Remove our event listeners
          // 最终移除事件监听
          window.removeEventListener('error', handleWindowError);
        };
    
        invokeGuardedCallbackImpl = invokeGuardedCallbackDev;
      }
    }
    
    • 它接收一系列的参数, 后续几个参数,它通过a,b,c,d,e,f来进行了一个命名
    • 看着前期的定义好像很简单,但是下面有一个 DEV 的判断
    • 这个方法 invokeGuardedCallbackDev 是最终 export 出去的
    • 注意,在上述 handleWindowError 中,
      • 被触发相关事件时,就会执行这个回调函数
      • 1 )当遇到跨域错误时,会做相关检测,并设置相关标识
      • 2 )如果遇到 onError被阻塞,也是做一些标识处理
    • 上述 evtType 的事件,一经调用,就会执行 上述的 callCallback 方法
      • callCallback 方法一旦被执行,就会执行参数中的 func 方法
      • 当后续 func 执行中出现错误,didError = false 就不会被执行
      • 同时,出现错误,会调用 handleWindowError 这个方法,里面的变量也会发生变化
    • 所以,里面的变量在整体流程中,非常有用
    • 还有,就是 在最后的两个嵌套 if中 if (didError) { if (!didSetError) {} else if(isCrossOriginError) }
      • 这时候会抛出错误, 分成两种情况,
      • 参考:https://legacy.reactjs.org/docs/cross-origin-errors.html
    • 为何不直接用try catch,而要用这种事件的方式来触发呢?
      • 因为会存在这么一个问题,在浏览器的调试工具中
      • 比方说,Sources面板,里面有个 Pause on exceptions 功能
      • 如果有try catch会自行处理,但开发者本意不希望它停在那边,选中 Pause on caught exceptions
      • 这样,即便通过trycatch捕获了这个错误,一旦代码报错了,我勾中了这个之后,代码也会因为报错而停止
      • 开启该功能,使代码在捕获的错误发生的位置暂停,这样更方便定位问题
      • 对于要去调试像 componentDidCatch 这种在组件内去处理错误的这种情况
      • 它就会因为代码停在这里,而导致我们没有办法去调试这部分相关的功能
      • 所以react为了防止这种情况的出现了,实现了这么一种方式
React源码分析4 — React生命周期详解 1 React生命周期流程调用流程可以参看上图。分为实例化,存在期和销毁三个不同阶段。介绍生命周期流程的文章很多,相信大部分同学也有所了解,我们就不详细分析了。很多同学肯定有疑问,这些方法在React内部是在哪些方法中被调用的呢,他们触发的时机又是什么时候呢。下面我们来详细分析。2 实例化生命周期getDefaultProps在React.creatClass()初始化组件类时,会调用getDefa 阅读详情

相关推荐

软考29-上午题-【数据结构】-排序

数据结构7种排序

qq_31532983的博客 1580

React 异常捕获和处理机制详解

本文全面介绍了React应用中的异常处理机制。主要内容包括:1)React为何需要异常处理,避免应用崩溃和数据不一致;2)错误边界的概念与实现,通过类组件捕获子组件错误;3)函数组件的异常处理方案,包括自定义Hook和错误边界包装;4)事件处理、异步代码等特殊场景的错误捕获技巧;5)全局错误监听和日志上报机制。文章强调分层处理的重要性,从组件级到应用级构建多层防护,同时兼顾用户体验和性能优化,最后提供了电商应用等实际场景的完整示例。

油墨香^-^的博客 2318

数据驱动的细胞动力学:从高通量成像到机器学习预测的完整实践指南

细胞动力学研究细胞群体随时间变化的规律和命运决策机制,是理解生命过程的基础。其核心原理在于将传统的定性观察转化为定量分析,通过高通量成像、单细胞测序等技术获取多维时序数据,并运用机器学习与统计模型挖掘数据中的深层模式。这一技术价值在于实现从“描述现象”到“预测行为”的范式转变,显著提升研究的客观性和可重复性。在应用场景上,它广泛应用于药物筛选、疾病机制研究和发育生物学等领域,能够加速靶点发现和疗效评估。本文聚焦于数据驱动的细胞动力学分析,详细拆解了从实验设计、图像处理、单细胞追踪到特征工程与建模预测的端到端

weixin_29056781的博客 269

深入了解 Claude Skills

ClaudeSkills是Anthropic推出的新功能,通过封装指令、脚本和资源,将通用AI助手Claude转变为专业能手。核心特性包括可组合性、可移植性、高效性和强大性。Skills采用"渐进式披露"设计,以SKILL.md文件为核心,包含元数据和详细说明,支持按需加载额外资源。该功能解决了零散定制和知识固化问题,允许用户构建和共享专业能力,适用于Claude各平台。

油墨香^-^的博客 2633

CAT24C16 EEPROM的I²C页写与页读底层实现

I²C是一种广泛应用于嵌入式系统的双线同步串行通信协议,其核心在于严格的时序控制、地址寻址机制与主从应答逻辑。理解I²C总线物理层(上拉电阻、SCL/SDA电气特性)、协议层(START/STOP、ACK/NACK、7位地址格式)及外设寄存器操作(如SR1状态标志、CCR时钟分频),是实现可靠通信的基础。在实际工程中,EEPROM类器件(如CAT24C16)因其非易失性、页缓冲区结构和写保护(WP)功能,成为数据持久化关键载体;其16字节页写约束、内部写周期(5–10ms)与地址指针自动递增等特性,直接决定

weixin_42591413的博客 389

【hadoop编译报错】(yarn install) on project hadoop-yarn-applications-catalog-webapp Failed to run task

ambari+bigtop自定义组件集成

TTBIGDATA的博客 1804

react取消捕获_react中的错误处理

解决的两个问题收集错误自定义事件实现try...catch错误捕获功能同时增加Pause on exceptions功能react\packages\shared\ReactErrorUtils.js用于存储错误以及是否发生错误的状态// Used by Fiber to simulate a try-catch.let hasError: boolean = false;let caughtEr...

weixin_39972519的博客 572

13、网络通信中的字节序与内存测试

本文主要探讨了网络通信中的字节序问题以及嵌入式系统中内存测试的相关内容。在网络通信部分,重点分析了大端序和小端序的差异,以及TCP/IP协议中字节序的转换机制,并介绍了相关的宏定义和实现方法。在内存测试部分,详细阐述了内存测试的目的、常见问题以及具体的测试策略,包括数据总线测试、地址总线测试和设备测试。通过这些内容,嵌入式程序员可以更好地理解并解决实际开发中可能遇到的字节序和内存问题,从而提高系统的稳定性和可靠性。

mmm90的博客 111

React Event 实现原理

React 元素的事件处理和 DOM元素的很相似。但是有一点语法上的不同: React事件绑定属性的命名采用驼峰式写法,而不是小写。 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM元素的写法) 并且 React 自己内部实现了一个合成事件,使用 React 的时候通常你不需要使用 addEvent...

weixin_33736832的博客 308

【推荐100个unity插件】动画重定向,快速在不同角色间共享动画,共用非人形Humanoid(泛型generic)动画——Retarget Pro

Retarget Pro是一款高效的Unity动画重定向工具,可快速在不同角色间共享动画。主要特点包括:1分钟快速设置,支持编辑器和运行时重定向;适用于人形、动物、武器等各类角色;提供基础重定向、IK重定向和FPS专用重定向三种功能模块;通过Rig组件和骨架资产实现骨骼链匹配,支持批量处理。插件包含示例项目和预设资源,操作简便且效果优于Unity原生Humanoid系统,特别适合处理手指等精细动画。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 549

《QGIS快速入门与应用基础》108:CGCS2000对应的投影坐标系

本文详细解析了CGCS2000地理坐标系对应的各类投影坐标系,包括高斯-克吕格3°带/6°带、UTM、地方独立投影和Web墨卡托投影。文章系统阐述了各投影类型的分带规则、参数设置、精度特性及适用场景,并提供了EPSG编码对照表和QGIS操作指南。通过"基准+投影"的绑定机制,这些投影坐标系实现了平面坐标与经纬度的精准转换,满足从大比例尺工程测量到Web地图服务等不同应用需求。内容涵盖投影原理、坐标格式、变形控制等关键技术要点,为GIS开发者和测绘人员提供了实用的参考信息。

LuckyHanMo的博客 545

react 事件机制04-事件触发原理(完结)

本文继续接上一篇文章涉及到的源码是基于 react15.6.1版本,虽然不是最新版本但是也不会影响我们对 react 事件机制的整体把握和理解。先简单的回顾下上一文,最...

zz_jesse的博客 1381

OpenHarmony开发一个App,安装到BearPi-HM Micro开发板

建议先阅读我们这篇,这里面详细介绍了,以及hap包安装的全过程。本篇是介绍如何开发一个App,然后安装到开发板上,比如hap包,无法安装等问题。

Halifax 1030

【React】1420- 搞定 React 异常捕获和处理机制

React 异常处理最重要的目标之一就是保持浏览器的Pause on exceptions行为。这里你不仅能学到 React 异常捕获的知识,还能学到如何模拟 try catch大纲React 开发和生产环境捕获异常的实现不同如何捕获异常,同时不吞没用户业务代码的异常如何模拟 try catch 捕获异常React 捕获用户所有的业务代码中的异常,除了异步代码无法捕获以外。React 使用 han...

pingan8787 1026

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

6748如何设置edma为事件触发方式_小前端读源码 React16.7.0(合成事件)

在上一篇文章中,我们说到了setState的过程。但是在阅读的过程中,发现setState的很多东西是依赖着合成事件去对我们的事件做一个分发处理和批量更新的。所以这篇文章就是以搞懂合成事件为目的对源码进行阅读的。Lam:小前端读源码 - React16.7.0(深入了解setState)zhuanlan.zhihu.com官方对合成事件的一些说明:SyntheticEvent – Rea...

weixin_39760295的博客 232

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【React深入】React事件机制

关于React事件的疑问 1.为什么要手动绑定 this 2. React事件和原生事件有什么区别 3. React事件和原生事件的执行顺序,可以混用吗 4. React事件如何解决跨浏览器兼容 5.什么是合成事件 下面是我阅读过源码后,将所有的执行流程总结出来的流程图,不会贴代码,如果你想阅读代码看看具体是如何实现的,可以根据流程图去源码里寻找。 事件注册 组件装载 / 更新。 通过lastProps、nextProps判断是否新增、删除..

chern1992的博客 395

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

React Native WebView Invoke 使用教程

React Native WebView Invoke 使用教程 项目介绍 react-native-webview-invoke 是一个用于在 React Native 应用中实现 WebView 与原生代码之间双向通信的库。通过这个库,开发者可以轻松地在 WebView 和 React Native 之间传递函数和数据,从而实现更复杂的交互功能。 项目快速启动 安装 首先,你需要安装 reac...

gitblog_00592的博客 449

react事件系统之事件触发

NodeNote,持续更新中react相关库源码浅析, react ts3 项目 概述,背景 <div id="app"></div> <div onclick="alert(1)">原生</div> class APP extends React.Component{ render(){ return ( ...

weixin_34303897的博客 1870

React-事件机制杂记

前提 最近通过阅读React官方文档的事件模块,有了一些思考和收获,在这里记录一下~ 调用方法时需要手动绑定this 先从一段官方代码看起: 代码中的注释提到了一句话: This binding is necessary to make this work in the callback this的绑定是必须的,其实这一块是比较容易理...

weixin_34228387的博客 144

【长文慎入】一文吃透 react 事件机制原理

写在前面上个月有幸研究了 react 事件机制这个知识点,并且在公司内部把自己的理解进行了分享。现在趁还算热乎赶紧的整理下来,留住这个长脸的时刻。大纲主要分为4大块儿,主...

zz_jesse的博客 1366

React高频面试题梳理,看看面试怎么答?(上)

前段时间准备面试,总结了很多,下面是我在准备React面试时,结合自己的实际面试经历,以及我以前源码分析的文章,总结出来的一些 React高频面试题目。 以前我写的源码分析的文章,并没有很多人看,因为大部分情况下你不需要深入源码也能懂得其中原理,并解决实际问题,这也是我总结这些面试题的原因,让你在更短的时间内获得更大的收益。 由于是以面试题的角度来讨论,所以某些点可能不能非常深入,我在问题下面都贴了相关链接,如果想深入理解,请点击这些文章。 由于题目较多,分为上、下两篇,本篇文章我们先来讨论如下19个

chern1992的博客 386

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万+

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

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

Wang的专栏 8836

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

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

Wang的专栏 6714

React 实现 2D 画板功能

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

Wang的专栏 4325

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

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

Wang的专栏 2803
上一篇: React16源码: React中commit阶段的commitRoot的主流程源码实现
下一篇: React16源码: React中commit阶段的commitBeforeMutationLifecycles的源码实现
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、付费专栏及课程。

余额充值