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

【React源码 - Fiber架构之Reconciler】 React源码-Fiber架构之Reconciler 阅读详情

reconcileChildren


1 )概述

  • 在更新了一个节点之后,拿到它的props.children
  • 要根据这个children里面的 ReactElement 来去创建子树的所有的 fiber 对象
  • 要根据 props.children 来生成 fiber 子树,然后判断 fiber 对象它是否是可以复用的
    • 因为我们在第一次渲染的时候,就已经渲染了整个 fiber 子树
    • 再有一个更新进来之后,state 变化可能会导致一些子节点产生一个新的变化
    • 可能就不能复用之前的 fiber 节点了,它里面的很多东西都变得不一样
    • 大部分情况下所有 fiber 节点都是可以可以重复利用的
    • 这个时候我们根据什么进行判断,是这里面的一个非常重要的一个点
  • 在这里就会拿出react当中的非常重要的key,列表根据key来优化

2 )源码

在 packages/react-reconciler/src/ReactFiberBeginWork.js#L137 中

export function reconcileChildren(
  current: Fiber | null,
  workInProgress: Fiber,
  nextChildren: any,
  renderExpirationTime: ExpirationTime,
) {
  if (current === null) {
    // If this is a fresh new component that hasn't been rendered yet, we
    // won't update its child set by applying minimal side-effects. Instead,
    // we will add them all to the child before it gets rendered. That means
    // we can optimize this reconciliation pass by not tracking side-effects.
    workInProgress.child = mountChildFibers(
      workInProgress,
      null,
      nextChildren,
      renderExpirationTime,
    );
  } else {
    // If the current child is the same as the work in progress, it means that
    // we haven't yet started any work on these children. Therefore, we use
    // the clone algorithm to create a copy of all the current children.

    // If we had any progressed work already, that is invalid at this point so
    // let's throw it out.
    workInProgress.child = reconcileChildFibers(
      workInProgress,
      current.child,
      nextChildren,
      renderExpirationTime,
    );
  }
}
  • 可见,根据 current 是否为 null 调用两个方法: mountChildFibers, reconcileChildFibers
    • 两个方法的区别,在第二个参数
    • 在前者方法中传递的是 null, 因为 第一次渲染,不存在 current.child
    • 因为第一次渲染的时候,都是父亲节点先渲染,子节点后渲染
    • 只有在后续的渲染过程当中,已经过第一次渲染了我们的父节点
    • 这个时候才有一个子节点存在,所以这是一个区别
    • 在 react-reconciler/src/ReactFiberBeginWork.js 中 的 reconcileChildren 调用这个 reconcileChildFibers
  • 看一下这两个方法,它们来自于 ReactChildFiber.js
    export const reconcileChildFibers = ChildReconciler(true);
    export const mountChildFibers = ChildReconciler(false);
    
  • 可见,上述两个方法的区别是 参数的 true 和 false
    • 这个参数的意思是: 表示是否要跟踪副作用
  • 进入 ChildReconciler,这个方法 1k 多行,这里不去全部摘抄
  • 用到哪里,逐个分析

整体框架

// 参数 shouldTrackSideEffects 表示是否要跟踪副作用
function ChildReconciler(shouldTrackSideEffects) {
  // ... 跳过很多代码

  // This API will tag the children with the side-effect of the reconciliation
  // itself. They will be added to the side-effect list as we pass through the
  // children and the parent.
  function reconcileChildFibers(
    returnFiber: Fiber,
    currentFirstChild: Fiber | null,
    newChild: any,
    expirationTime: ExpirationTime,
  ): Fiber | null {
    // 省略很多代码
    // Remaining cases are all treated as empty.
    return deleteRemainingChildren(returnFiber, currentFirstChild);
  }

  return reconcileChildFibers;
}
  • 在 ChildReconciler 方法的最后, return reconcileChildFibers;,先看下这个方法

    // This API will tag the children with the side-effect of the reconciliation
    // itself. They will be added to the side-effect list as we pass through the
    // children and the parent.
    function reconcileChildFibers(
      returnFiber: Fiber,
      currentFirstChild: Fiber | null,
      newChild: any,
      expirationTime: ExpirationTime,
    ): Fiber | null {
      // This function is not recursive.
      // If the top level item is an array, we treat it as a set of children,
      // not as a fragment. Nested arrays on the other hand will be treated as
      // fragment nodes. Recursion happens at the normal flow.
    
      // Handle top level unkeyed fragments as if they were arrays.
      // This leads to an ambiguity between <>{[...]}</> and <>...</>.
      // We treat the ambiguous cases above the same.
    
      // newChild 是计算出来的 新children
      // 这个节点是一个 top level 的节点,因为 <></> 这种类型会匹配 REACT_FRAGMENT_TYPE
      // 符合以下就是没有key的 topLevel节点
      const isUnkeyedTopLevelFragment =
        typeof newChild === 'object' &&
        newChild !== null &&
        newChild.type === REACT_FRAGMENT_TYPE &&
        newChild.key === null;
      // 如果匹配了,那么 Fragment 是没有任何的操作更新的, 本身并没有什么实际的意义
      // 如果匹配了,则将newChild赋值
      if (isUnkeyedTopLevelFragment) {
        newChild = newChild.props.children;
      }
    
      // Handle object types
      const isObject = typeof newChild === 'object' && newChild !== null;
    
      // 如果是对象,说明有下面两种情况
      // 下面两种方法调用相似,都是基于 placeSingleChild 传递不同参数
      // 一个是 reconcileSingleElement
      // 另一个是 reconcileSinglePortal
      if (isObject) {
        switch (newChild.$$typeof) {
          // 匹配 REACT_ELEMENT,是通过 React.createElement 产生的
          case REACT_ELEMENT_TYPE:
            return placeSingleChild(
              reconcileSingleElement(
                returnFiber,
                currentFirstChild,
                newChild,
                expirationTime,
              ),
            );
          // 匹配 REACT_PORTAL, 是通过 ReactDOM.createPortal
          case REACT_PORTAL_TYPE:
            return placeSingleChild(
              reconcileSinglePortal(
                returnFiber,
                currentFirstChild,
                newChild,
                expirationTime,
              ),
            );
        }
      }
    
      // 匹配到 string 和 number 类就是 text类型的Node
      if (typeof newChild === 'string' || typeof newChild === 'number') {
        return placeSingleChild(
          reconcileSingleTextNode(
            returnFiber,
            currentFirstChild,
            '' + newChild,
            expirationTime,
          ),
        );
      }
    
      // 匹配到数组
      if (isArray(newChild)) {
        return reconcileChildrenArray(
          returnFiber,
          currentFirstChild,
          newChild,
          expirationTime,
        );
      }
      
      // 匹配到可迭代的对象
      if (getIteratorFn(newChild)) {
        return reconcileChildrenIterator(
          returnFiber,
          currentFirstChild,
          newChild,
          expirationTime,
        );
      }
    
      // 以上都没有匹配,但仍然是对象,则 throw error
      if (isObject) {
        throwOnInvalidObjectType(returnFiber, newChild);
      }
    
      // 忽略 DEV
      if (__DEV__) {
        if (typeof newChild === 'function') {
          warnOnFunctionType();
        }
      }
    
      // 匹配到 undefined 的对象
      if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) {
        // If the new child is undefined, and the return fiber is a composite
        // component, throw an error. If Fiber return types are disabled,
        // we already threw above.
        switch (returnFiber.tag) {
          // 匹配到 ClassComponent 忽略
          case ClassComponent: {
            if (__DEV__) {
              const instance = returnFiber.stateNode;
              if (instance.render._isMockFunction) {
                // We allow auto-mocks to proceed as if they're returning null.
                break;
              }
            }
          }
          // Intentionally fall through to the next case, which handles both
          // functions and classes
          // eslint-disable-next-lined no-fallthrough
          // 匹配到 FunctionComponent 提醒
          case FunctionComponent: {
            const Component = returnFiber.type;
            invariant(
              false,
              '%s(...): Nothing was returned from render. This usually means a ' +
                'return statement is missing. Or, to render nothing, ' +
                'return null.',
              Component.displayName || Component.name || 'Component',
            );
          }
        }
      }
    
      // Remaining cases are all treated as empty.
      // 以上都不符合,则 是 null, 删除现有所有 children
      // 新的 props.children 都是 null, 老的 props 节点都应该被删除
      return deleteRemainingChildren(returnFiber, currentFirstChild);
    }
    
  • 接下来看不同节点的更新 reconcileSingleElement

    // 从当前已有的所有子节点中,找到一个可以复用新的子节点的Fiber对象
    // 复用它之后,把剩下兄弟节点全部删掉
    function reconcileSingleElement(
      returnFiber: Fiber,
      currentFirstChild: Fiber | null, // 是当前已有的fiber节点,初次渲染没有,后续渲染后很可能存在
      element: ReactElement,
      expirationTime: ExpirationTime,
    ): Fiber {
      // 获取 key 和 child
      const key = element.key;
      let child = currentFirstChild;
      // child 存在
      while (child !== null) {
        // TODO: If key === null and child.key === null, then this only applies to
        // the first item in the list.
        if (child.key === key) {
          // 注意这个判断
          if (
            child.tag === Fragment
              ? element.type === REACT_FRAGMENT_TYPE // 是否是 frament
              : child.elementType === element.type // 新老 element type
          ) {
            // 删除 已存在当前节点的兄弟节点
            // 为何要删除兄弟节点,因为我们这次渲染只有一个节点,老的节点有兄弟节点,新的节点只有一个,删除之
            deleteRemainingChildren(returnFiber, child.sibling);
            const existing = useFiber(
              child,
              element.type === REACT_FRAGMENT_TYPE
                ? element.props.children
                : element.props,
              expirationTime,
            );
            // 挂载属性
            existing.ref = coerceRef(returnFiber, child, element);
            existing.return = returnFiber;
            if (__DEV__) {
              existing._debugSource = element._source;
              existing._debugOwner = element._owner;
            }
            // 找到可复用节点,直接return
            return existing;
          } else {
            // 条件不符合,删除节点并退出 
            deleteRemainingChildren(returnFiber, child);
            break;
          }
        } else {
          // key 不同,则删除
          deleteChild(returnFiber, child);
        }
        // 当前兄弟节点 等于 child 再次进入while循环
        child = child.sibling;
      }
      // 创建新的节点, 基于各种不同的类型,调用不同的创建 Fiber的方式
      if (element.type === REACT_FRAGMENT_TYPE) {
        const created = createFiberFromFragment(
          element.props.children, // 注意这个参数
          returnFiber.mode,
          expirationTime,
          element.key,
        );
        created.return = returnFiber;
        return created;
      } else {
        const created = createFiberFromElement(
          element,
          returnFiber.mode,
          expirationTime,
        );
        created.ref = coerceRef(returnFiber, currentFirstChild, element);
        created.return = returnFiber;
        return created;
      }
    }
    
    • 进入 createFiberFromFragment
      export function createFiberFromFragment(
        elements: ReactFragment,
        mode: TypeOfMode,
        expirationTime: ExpirationTime,
        key: null | string,
      ): Fiber {
        const fiber = createFiber(Fragment, elements, key, mode);
        fiber.expirationTime = expirationTime;
        return fiber;
      }
      
      // This is a constructor function, rather than a POJO constructor, still
      // please ensure we do the following:
      // 1) Nobody should add any instance methods on this. Instance methods can be
      //    more difficult to predict when they get optimized and they are almost
      //    never inlined properly in static compilers.
      // 2) Nobody should rely on `instanceof Fiber` for type testing. We should
      //    always know when it is a fiber.
      // 3) We might want to experiment with using numeric keys since they are easier
      //    to optimize in a non-JIT environment.
      // 4) We can easily go from a constructor to a createFiber object literal if that
      //    is faster.
      // 5) It should be easy to port this to a C struct and keep a C implementation
      //    compatible.
      const createFiber = function(
        tag: WorkTag,
        pendingProps: mixed, // 对于 fragment来说,props只有children, 直接把children作为props
        key: null | string,
        mode: TypeOfMode,
      ): Fiber {
        // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
        return new FiberNode(tag, pendingProps, key, mode);
      };
      
    • 以上的 fragment 可以在 ReactFiberBeginWork.js 中的 updateFragment 方法中找到验证
      function updateFragment(
        current: Fiber | null,
        workInProgress: Fiber,
        renderExpirationTime: ExpirationTime,
      ) {
        // 看这里,直接通过 .pendingProps 而非 props.children 获取,参考上述 createFiber 写明原因
        const nextChildren = workInProgress.pendingProps;
        reconcileChildren(
          current,
          workInProgress,
          nextChildren,
          renderExpirationTime,
        );
        return workInProgress.child;
      }
      
    • 进入 createFiberFromElement
      export function createFiberFromElement(
        element: ReactElement,
        mode: TypeOfMode,
        expirationTime: ExpirationTime,
      ): Fiber {
        let owner = null;
        if (__DEV__) {
          owner = element._owner;
        }
        // 获取各类属性
        const type = element.type;
        const key = element.key;
        const pendingProps = element.props;
        // 创建 Fiber
        const fiber = createFiberFromTypeAndProps(
          type,
          key,
          pendingProps,
          owner,
          mode,
          expirationTime,
        );
        if (__DEV__) {
          fiber._debugSource = element._source;
          fiber._debugOwner = element._owner;
        }
        return fiber;
      }
      
    • 进入 createFiberFromTypeAndProps
      // 这个方法比较复杂,要判断不同的 type 给 fiber 对象增加 不同的 tag
      // 主要是去匹配 fiberTag
      export function createFiberFromTypeAndProps(
        type: any, // React$ElementType
        key: null | string,
        pendingProps: any,
        owner: null | Fiber,
        mode: TypeOfMode,
        expirationTime: ExpirationTime,
      ): Fiber {
        let fiber;
        // 组件tag未知时的初始化配置 未指定状态
        let fiberTag = IndeterminateComponent;
        // The resolved type is set if we know what the final type will be. I.e. it's not lazy.
        let resolvedType = type;
        // 根据不同类型来处理 fiberTag
        if (typeof type === 'function') {
          // 判断是否有 constructor 方法
          /*
          function shouldConstruct(Component: Function) {
            const prototype = Component.prototype;
            // 注意,这里 isReactComponent 是一个 {}
            return !!(prototype && prototype.isReactComponent);
          }
          */
          if (shouldConstruct(type)) {
            fiberTag = ClassComponent;
          }
        } else if (typeof type === 'string') {
          fiberTag = HostComponent;
        } else {
          getTag: switch (type) {
            case REACT_FRAGMENT_TYPE:
              return createFiberFromFragment(
                pendingProps.children,
                mode,
                expirationTime,
                key,
              );
            case REACT_CONCURRENT_MODE_TYPE:
              return createFiberFromMode(
                pendingProps,
                mode | ConcurrentMode | StrictMode,
                expirationTime,
                key,
              );
            case REACT_STRICT_MODE_TYPE:
              return createFiberFromMode(
                pendingProps,
                mode | StrictMode,
                expirationTime,
                key,
              );
            case REACT_PROFILER_TYPE:
              return createFiberFromProfiler(pendingProps, mode, expirationTime, key);
            case REACT_SUSPENSE_TYPE:
              return createFiberFromSuspense(pendingProps, mode, expirationTime, key);
            default: {
              if (typeof type === 'object' && type !== null) {
                switch (type.$$typeof) {
                  case REACT_PROVIDER_TYPE:
                    fiberTag = ContextProvider;
                    break getTag;
                  case REACT_CONTEXT_TYPE:
                    // This is a consumer
                    fiberTag = ContextConsumer;
                    break getTag;
                  case REACT_FORWARD_REF_TYPE:
                    fiberTag = ForwardRef;
                    break getTag;
                  case REACT_MEMO_TYPE:
                    fiberTag = MemoComponent;
                    break getTag;
                  case REACT_LAZY_TYPE:
                    fiberTag = LazyComponent;
                    resolvedType = null;
                    break getTag;
                }
              }
              let info = '';
              if (__DEV__) {
                if (
                  type === undefined ||
                  (typeof type === 'object' &&
                    type !== null &&
                    Object.keys(type).length === 0)
                ) {
                  info +=
                    ' You likely forgot to export your component from the file ' +
                    "it's defined in, or you might have mixed up default and " +
                    'named imports.';
                }
                const ownerName = owner ? getComponentName(owner.type) : null;
                if (ownerName) {
                  info += '\n\nCheck the render method of `' + ownerName + '`.';
                }
              }
              invariant(
                false,
                'Element type is invalid: expected a string (for built-in ' +
                  'components) or a class/function (for composite components) ' +
                  'but got: %s.%s',
                type == null ? type : typeof type,
                info,
              );
            }
          }
        }
        // 最终创建 Fiber
        fiber = createFiber(fiberTag, pendingProps, key, mode);
        fiber.elementType = type;
        fiber.type = resolvedType;
        fiber.expirationTime = expirationTime;
      
        return fiber;
      }
      
    • 以上,reconcileSingleElement 就完了
  • 进入 reconcileSingleTextNode

    function reconcileSingleTextNode(
      returnFiber: Fiber,
      currentFirstChild: Fiber | null,
      textContent: string,
      expirationTime: ExpirationTime,
    ): Fiber {
      // There's no need to check for keys on text nodes since we don't have a
      // way to define them.
      // 处理 原生 标签
      if (currentFirstChild !== null && currentFirstChild.tag === HostText) {
        // We already have an existing node so let's just update it and delete
        // the rest.
        // 删除兄弟节点,新节点只是一个纯的文本节点
        deleteRemainingChildren(returnFiber, currentFirstChild.sibling);
        // 基于 useFiber 复用当前节点
        const existing = useFiber(currentFirstChild, textContent, expirationTime);
        existing.return = returnFiber;
        return existing;
      }
      // The existing first child is not a text node so we need to create one
      // and delete the existing ones.
      deleteRemainingChildren(returnFiber, currentFirstChild);
      const created = createFiberFromText(
        textContent,
        returnFiber.mode,
        expirationTime,
      );
      created.return = returnFiber;
      return created;
    }
    
    • 这个流程就比较简单了
  • 现在我们主要看下 deleteRemainingChildren 这个api

    function deleteRemainingChildren(
      returnFiber: Fiber, // 当前正在更新的节点
      currentFirstChild: Fiber | null, // 子节点
    ): null {
      // 这是第一次渲染的时候,没有子节点
      // 直接 return
      if (!shouldTrackSideEffects) {
        // Noop.
        return null;
      }
    
      // TODO: For the shouldClone case, this could be micro-optimized a bit by
      // assuming that after the first child we've already added everything.
      // 一个个的删除
      let childToDelete = currentFirstChild;
      while (childToDelete !== null) {
        deleteChild(returnFiber, childToDelete);
        childToDelete = childToDelete.sibling;
      }
      return null;
    }
    
    • 进入 deleteChild
      // 可以看到这里没有实施删除的操作,只是改变了节点上的 effectTag
      // 这里我们只更新 Fiber Tree, 如果真的要 delete 就会影响到 dom节点
      // 所以删除的流程不在这里做,只有在下个阶段,也就是 commit 阶段来做
      // 就是把Fiber Tree 需要更新的流程都过一遍之后,把整个需要更新的属性
      // 通过 firstEffect,lastEffect 这种链条,最终链到根节点上面
      // 最终要执行更新 只需要在 commit 阶段拿到 根节点上面的 这种链条把每个节点去执行即可
      // 在处理更新的时候任务是可以中断的,但是在 commit 阶段任务是不可中断的
      function deleteChild(returnFiber: Fiber, childToDelete: Fiber): void {
        if (!shouldTrackSideEffects) {
          // Noop.
          return;
        }
        // Deletions are added in reversed order so we add it to the front.
        // At this point, the return fiber's effect list is empty except for
        // deletions, so we can just append the deletion to the list. The remaining
        // effects aren't added until the complete phase. Once we implement
        // resuming, this may not be true.
        const last = returnFiber.lastEffect;
        // 存在 last
        if (last !== null) {
          last.nextEffect = childToDelete;
          returnFiber.lastEffect = childToDelete;
        } else {
          // 不存在 last
          returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
        }
        childToDelete.nextEffect = null; // 已经是要删除的节点,上面的其他副作用都是没有任何意义的
        // effectTag 就是告诉后续的 commit 阶段,对于这个节点需要执行什么操作,可以看到,这里是删除
        childToDelete.effectTag = Deletion; // 只需要设置这个即可
      }
      
  • reconcileChildrenArray 和 reconcileChildrenIterator 这两个api比较复杂,先跳过

  • 其他的 API 都是比较简单了

react源码解析8.render阶段 react源码解析8.render阶段 视频讲解(高效学习):进入学习 往期文章: 1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录结构和调试 5.jsx&核心api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.c 阅读详情

相关推荐

海康VisionMaster图形定位实战:十字形Mark点精准匹配技巧

本文深入解析了海康VisionMaster图形定位模块在工业自动化中实现十字形Mark点精准匹配的实战技巧。文章从ROI设置、核心参数调优(如定位方式、尺度模式、对比度阈值)到工业场景应用与避坑指南,系统性地分享了提升匹配成功率和稳定性的关键步骤,帮助工程师应对复杂现场环境,实现高效、可靠的视觉定位。

weixin_29285605的博客 261

React 的源码与原理解读(六):reconcileChildren 与 DIFF 算法

本节的我们将从 上一节留下的问题出发,谈谈 **reconcileChildren()** 中怎么样最终生成 fiber 结点,其中我们会谈到 React 核心的 **DIFF 算法**,他的核心 —— 复用怎么实现,同时他是怎么样把比较的时间复杂度进行了优化

weixin_46463785的博客 1115

ORCAD原理图关联封装时出现ERROR(ORCIS-6245)、ERROR(ORCIS-6013)问题

1、当你进行如下操作时: 系统先是提示你出现ERROR(ORCIS-6245)然后再确定后再出现ERROR(ORCIS-6013)问题 是由于你的数据库的路径不对。 具体操作方法如下:1、先找到你的CAPTURE.INI文件。 2、用记事本打开CAPTURE.INI。找到下图路径 3、在你的Orcad capture CIS原理图软件中点击 Options------>CIS con...

weixin_42304393的博客 2万+

React16源码: React中的reconcileChildIterator和reconcileChildrenArray的源码实现

在 reconcileChildFibers 函数中调用的 reconcileChildrenIterator。在 reconcileChildFibers 函数中调用的 reconcileChildrenArray。新老children的对比过程,以及判断节点是否可复用的过程,这个过程会涉及到react的一个算法。先看下 reconcileChildrenArray 这个API。尽量减少 数组的遍历次数,达到复用节点的过程。

Wang的专栏 1540

手把手教你逆向京东搜索接口:H5ST 556位参数生成与V8补环境技巧

本文深入解析了京东搜索接口中关键的H5ST 556位参数生成机制,并提供了详细的逆向实战指南。针对其复杂的反爬虫环境检测,文章重点介绍了通过链式补环境技巧,在Node.js中完整模拟浏览器环境(包括原型链检测和指纹验证)的方法,帮助开发者成功绕过防护并生成有效参数。

weixin_29315091的博客 485

Arm A-profile架构RAS系统设计:可靠性、可用性与可服务性解析

在计算机体系结构中,可靠性(Reliability)、可用性(Availability)和可服务性(Serviceability)是构建高可信系统的核心要素。RAS系统通过硬件错误检测、隔离和恢复机制,确保系统持续稳定运行。其技术原理包括ECC内存纠错、冗余执行单元和错误传播阻断等关键技术,可显著降低数据中心等关键业务场景的故障率。现代芯片设计中,Arm A-profile架构提供标准化的RAS框架,涵盖从内存子系统到计算单元的全方位错误管理。通过分层防御策略和统一错误记录格式,实现硬件错误可追溯、可修复。

weixin_30920853的博客 358

Deep In React 系列之详解 React 16 的 Diff 策略

阅读本文大约需要 9 分钟这是我 Deep In React 系列的第二篇文章,如果还没有读过的强烈建议你先读第一篇:详谈 React Fiber 架构(1)。前言我相信...

奇舞周刊 835

010Editor实战:5分钟破解Zip伪加密文件(附BUUCTF真题解析)

本文详细介绍了如何使用010Editor快速破解Zip伪加密文件,包括BUUCTF真题的完整解析。通过修改关键字节,轻松解除伪加密状态,适用于CTF竞赛和实际工作场景,提升文件处理效率。

weixin_29325007的博客 327

05【React再造之旅】从零实现一个React(下)

写在前面 本文继续上一节文章,来介绍下剩余的知识,如下: Render和Commit阶段 调和过程 函数组件 Hooks 我们接下来的部分就依次介绍下这些知识点。 代码获取 本文涉及到的代码全部上传至码云,需要的同学请在下面地址中获取: https://gitee.com/XuQianWen/zerocreate_react://gitee.com/XuQianWen/zerocreate_react ...

X北辰北的博客 813

B3640 T3 句子反转

要求将这些单词倒序输出。而且对于每个单词,如果是小写词,应当转为大写;如果是大写词,应当转为小写;如果是自然数,应该倒转输出。给定一行句子,每个词之间用空格隔开,要么是全小写英文单词,要么是全大写英文单词,要么是自然数。第一次做的时候0分,两个小时没做出来。仅一行,表示程序对句子的处理结果。仅一行,即需要反转的句子。

小前日记 366

《Java开发及前端最全面试题-Offer直通车》目录

Java开发是需求最广,工资高的细分领域,同时也是会的人最多,有的公司招1个Java开发,要面试几十甚至上百面试者,同时要求很高,要求通晓技术栈很多及很深深度。如果你正准备面试,想要脱颖而出,那么《Java开发及前端最全面试题-Offer直通车》是你的不二选择。本书汇集了多篇超过1万字的精华内容,无论是Java基础、数据库、SpringBoot和SpringCloud等必问的,还是前端、k8s等容器和虚拟化和大数据各类技术面试,本书都为你提供了最全面的试题和参考答案。

大模型大数据攻城狮的专栏 1180

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

`Mode` 组件是 react提供给我们的原生组件, 一共有两个: `ConcurrentMode` 和 `StrictMode`, 对于这两个 Mode 的更新过程最终调用的都是 `updateMode` 的方法, 它们执行的过程非常的简单,就是通过 `reconcileChildren` 去创建children就可以了

Wang的专栏 1056

1、JMP脚本编程全面指南:从基础到高级应用

本博客全面介绍了JMP脚本编程的各个方面,从JMP基础和JSL入门,到数据类型、数据结构、编程方法、数据表操作、图形与三维场景脚本,再到应用程序创建与扩展功能。内容涵盖脚本工具使用、常见任务实现、兼容性说明及未来发展趋势,旨在帮助用户掌握JMP脚本语言的强大功能,提升数据分析的自动化与定制化能力。适合从初学者到高级用户的深入学习与实践参考。

flink9streamer的博客 267

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

定位到 packages/react-reconciler/src/ReactFiberBeginWork.js。的 beginWork 函数,在 beginWork 下面的 执行 switch case 中。进入到 updateFunctionComponent 方法。

Wang的专栏 969

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

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

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

详解 React 16 的 Diff 策略

阅读本文大约需要 9 分钟这是我 Deep In React 系列的第二篇文章,如果还没有读过的强烈建议你先读第一篇:详谈 React Fiber 架构(1)。前言我相信...

全栈前端精选 79

jre9下载 jdk9

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

React 16.12.0 源码解读(二)之任务调度

React任务调度部分的源码梳理和解读。

Babyfaceqian的博客 257

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

React 16 源码解析笔记 05 - render阶段03 workLoopSync 解析

workLoopSync 解析 上面已经把 workInProgress Fiber 树中的 rootFiber 构建完成,接下来要构建它的子级 fiber 对象了。 这个子级 fiber 对象就是 render 方法的第一个参数,它在代码走到 workLoopSync 方法时开始被构建。 workLoopSync 就是开启一个循环,以同步的方式开始构建 fiber 对象 workLoopSync workLoopSync 仅仅开启了一个 while 循环,用于构建 rootFiber 对象的所有子级 fi

皮蛋很白的博客 735

react16源码(Fiber架构)

react16-Fiber架构:改变了之前react的组件渲染机制,新的架构使原来同步渲染的组件现在可以异步化,可中途中断渲染,执行更高优先级的任务,释放浏览器主线程。   React 核心算法的更新 —— 这次更新提供了一个从底层重写了 React 的 reconciliation 算法(译注:reconciliation 算法,是 React 用来比较两棵 DOM 树差异、从而判断哪一部分应...

weixin_33811961的博客 162

react中的fiber和初次渲染

fiber是指组件上将要完成或者已经完成的任务,每个组件可以一个或者多个。

lwl12345678_的博客 661

手写迷你React:300行代码带你彻底理解React核心原理

通过 300 行代码,我们揭开了 React 的神秘面纱。虚拟 DOM只是一个普通对象,描述了 UI 结构协调算法通过比较决定最小更新,而不是全部重绘Hooks通过调用顺序管理状态,因此有那些使用限制​写出更可靠的代码​:知道 React 如何工作,避免踩坑​高效调试问题​:当 UI 异常时,能快速定位原因​做出合理设计​:基于 React 特性设计应用架构​最好的学习方式是实践​:修改这个迷你 React,添加新功能,遇到问题并解决它。这会比阅读任何文章都让你更深入理解 React。

Billow_lamb的博客 306

200行代码实现简版react

现在(2018年)react在前端开发领域已经越来越

weixin_34254823的博客 310

React diff 算法

前言 很久以前写过一篇了解虚拟DOM的文章,主要讲解了vue为什么会使用虚拟 DOM 以及 VUE 的 diff 算法。最近技术栈迁移到了 React,就好好研究了一下 React diff 算法的实现。 React Fiber 在了解 React diff 算法之前,先了解 React Fiber 相关的知识,将有助于后面对 diff 算法中比对的理解。React 16版本之后推出了 Fiber 的概念,React Fiber是对核心算法的一次重新实现,基本本文主要是讲 diff 算法,因此忽略分.

大灰狼的小绵羊哥哥的博客 610

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
上一篇: React16源码: React中的FunctionComponent的源码实现
下一篇: React16源码: React中的reconcileChildIterator和reconcileChildrenArray的源码实现
Wang's Blog
博客等级 码龄12年 7434粉丝 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、付费专栏及课程。

余额充值