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

这篇具有很好参考价值的文章主要介绍了React16源码: React中的reconcileChildren的源码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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; // 只需要设置这个即可
      }
      
  • reconcileChildrenArrayreconcileChildrenIterator 这两个api比较复杂,先跳过

  • 其他的 API 都是比较简单了文章来源地址https://www.toymoban.com/news/detail-808019.html

到了这里,关于React16源码: React中的reconcileChildren的源码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • React16源码: React中的performWork的源码实现

    performWork 1 )概述 performWork 涉及到在调度完成,或者同步任务进来之后整个 root 节点链条如何更新 怎么更新一棵 Fiber 树,它的每一个节点是如何被遍历到,以及如何进行更新操作 A. 在执行 performWork 时候,是否有 deadline 的区分 deadline 是通过 reactschedule 它的一个时间片,更新

    2024年01月17日
    浏览(39)
  • React16源码: React中的updateHostRoot的源码实现

    HostRoot 的更新 1 )概述 HostRoot 是一个比较特殊的节点, 因为在一个react应用当中 它只会有一个 HostRoot , 它对应的 Fiber 对象是我们的 RootFiber 对象 重点在于它的更新过程 2 )源码 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js#L612 HostRoot 创建更新的过程就是在 ReactFiberReconcile

    2024年01月22日
    浏览(43)
  • React16源码: React中的updateClassComponent的源码实现

    ClassComponent 的更新 1 ) 概述 在 react 中 class component,是一个非常重要的角色 它承担了 react 中 更新整个应用的API setState forceUpdate 在react当中,只有更新了state之后,整个应用才会重新进行渲染 在 class component 中, 它的逻辑相对复杂 2 )源码 在 packages/react-reconciler/src/ReactFiberB

    2024年01月21日
    浏览(38)
  • React16源码: React中的renderRoot的源码实现

    renderRoot 1 )概述 renderRoot 是一个非常复杂的方法 这个方法里处理很多各种各样的逻辑, 它主要的工作内容是什么? A. 它调用 workLoop 进行循环单元更新 遍历整个 Fiber Tree,把每一个组件或者 dom 节点对应的 Fiber 节点拿出来单一的进行更新,这是一个循环的操作 把整棵 Fiber T

    2024年01月17日
    浏览(41)
  • React16源码: React中的HostComponent & HostText的源码实现

    HostComponent HostText 1 )概述 HostComponent 就是我们dom原生的这些节点, 如: div, span, p 标签这种 使用的是小写字母开头的这些节点一般都认为它是一个 HostComponent HostText ,它是单纯的文本节点 主要关注它们的一个更新过程 2 )源码 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js 进

    2024年01月24日
    浏览(39)
  • React16源码: React中的setState和forceUpdate源码实现

    setState 和 forceUpdate 1 ) 概述 通过 class component 内部的 setState ,以及 forceUpdate 去更新一个组件的过程 在react的应用当中,我们只有 ReactDOM.render setState ,以及 forceUpdate 这几种种方式去更新react的应用是合理的,其他没有什么特别常用的方式去更新了 而且react官方推荐的也是用

    2024年01月25日
    浏览(37)
  • React16源码: React中的update和updateQueue的源码实现

    React中的update和updateQueue 1 )概述 在 ReactDOM.render 过程中,还需要创建一个 update 对象 update 用于记录组件状态的改变的一个对象,它存放于Fiber对象的 updateQueue 中 updateQueue ,它是一个单向链表的结构,一次整体的更新过程当中 可能在这个queue里会存在多 Update 在这次更新的过

    2024年02月02日
    浏览(37)
  • React16源码: React中的PortalComponent创建, 调和, 更新的源码实现

    PortalComponent 1 )概述 React Portal之所以叫Portal,因为做的就是和“传送门”一样的事情 render到一个组件里面去,实际改变的是网页上另一处的DOM结构 主要关注 portal的创建, 调和, 更新过程 2 )源码 定位到 packages/react-dom/src/client/ReactDOM.js#L576 这里调用的是 ReactPortal.createPortal ,

    2024年01月21日
    浏览(41)
  • React16源码: React中的不同的expirationTime的源码实现

    不同的 expirationTime 1 )概述 在React中不仅仅有异步任务 大部分情况下都是同步的任务,所以会有不同 expirationTime 的存在 2 )种类 A. Sync 模式,优先级最高 任务创建完成之后,立马更新到真正的dom里面 是一个创建即更新的流程 B. Async 模式, 异步模式 会有一个调度 包含一系列

    2024年02月01日
    浏览(36)
  • React16源码: React中的reconcileChildIterator和reconcileChildrenArray的源码实现

    reconcileChildIterator 和 reconcileChildrenArray 1 )概述 在react更新某一个节点的时候,要根据这个节点,它的类型去获取它的children 比如说如果是 Function Component,它要调用这个 component 计算出它的return的属性 return的属性可能是一个数组,可能是单个的 ReactElement,可能是 number, string

    2024年01月20日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包