React16源码: React中的completeWork对HostComponent处理的源码实现

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

HostComponent


1 )概述

  • completeWork 当中,我们需要对 HostComponent 的一些操作有哪些?
    • 首先在一次更新而不是初次渲染的情况下
    • 需要去 diffProperties 来计算,需要更新的内容
    • 也就是在 vdom 中去进行一个对比来判断这一个节点是否需要真的去更新它
    • 以此来最低程度的去更新整个 dom 的一个过程
    • 对于不同 dom property,它有一些不同的处理方式

2 )源码

定位到 packages/react-reconciler/src/ReactFiberCompleteWork.js#L581

找到 case HostComponent文章来源地址https://www.toymoban.com/news/detail-818277.html

case HostComponent: {
  // 跳过
  popHostContext(workInProgress);
  // 跳过
  const rootContainerInstance = getRootHostContainer();
  const type = workInProgress.type;
  // 不是第一次渲染,也就是更新的时候
  if (current !== null && workInProgress.stateNode != null) {
    updateHostComponent(
      current,
      workInProgress,
      type,
      newProps,
      rootContainerInstance,
    );

    if (current.ref !== workInProgress.ref) {
      markRef(workInProgress); // 跳过
    }
  } else {
    // 第一次挂载渲染
    // 没有 props 说明有问题,提示
    if (!newProps) {
      invariant(
        workInProgress.stateNode !== null,
        'We must have new props for new mounts. This error is likely ' +
          'caused by a bug in React. Please file an issue.',
      );
      // This can happen when we abort work.
      break;
    }
    // 跳过
    const currentHostContext = getHostContext();
    // TODO: Move createInstance to beginWork and keep it on a context
    // "stack" as the parent. Then append children as we go in beginWork
    // or completeWork depending on we want to add then top->down or
    // bottom->up. Top->down is faster in IE11.
    let wasHydrated = popHydrationState(workInProgress);
    if (wasHydrated) {
      // TODO: Move this and createInstance step into the beginPhase
      // to consolidate.
      if (
        prepareToHydrateHostInstance(
          workInProgress,
          rootContainerInstance,
          currentHostContext,
        )
      ) {
        // If changes to the hydrated node needs to be applied at the
        // commit-phase we mark this as such.
        markUpdate(workInProgress);
      }
    } else {
      // 第一次挂载
      // 注意,这里,创建 element的过程
      let instance = createInstance(
        type,
        newProps,
        rootContainerInstance,
        currentHostContext,
        workInProgress,
      );

      // 第一次渲染,要添加子节点
      appendAllChildren(instance, workInProgress, false, false);

      // Certain renderers require commit-time effects for initial mount.
      // (eg DOM renderer supports auto-focus for certain elements).
      // Make sure such renderers get scheduled for later work.
      if (
        // 主要功能: 对dom节点上面的可能的事件监听,需要初始化整个react的事件体系
        // 这个函数返回当前节点 是否需要 autoFocus
        finalizeInitialChildren(
          instance,
          type,
          newProps,
          rootContainerInstance,
          currentHostContext,
        )
      ) {
        // 如果上面if最终是 autofocus, 就要在这个 workInProgress 上面去增加 Update 的 SideEffect
        // 来告诉后续commit的时候要执行一定的操作
        markUpdate(workInProgress);
      }
      workInProgress.stateNode = instance; // 挂载 instance
    }

    if (workInProgress.ref !== null) {
      // If there is a ref on a host node we need to schedule a callback
      markRef(workInProgress);
    }
  }
  break;
}
  • 进入 createInstance
    // packages/react-dom/src/client/ReactDOMHostConfig.js#L167
    // 这个方法就是创建节点的过程
    export function createInstance(
      type: string,
      props: Props,
      rootContainerInstance: Container,
      hostContext: HostContext,
      internalInstanceHandle: Object,
    ): Instance {
      let parentNamespace: string;
      if (__DEV__) {
        // TODO: take namespace into account when validating.
        const hostContextDev = ((hostContext: any): HostContextDev);
        validateDOMNesting(type, null, hostContextDev.ancestorInfo);
        if (
          typeof props.children === 'string' ||
          typeof props.children === 'number'
        ) {
          const string = '' + props.children;
          const ownAncestorInfo = updatedAncestorInfo(
            hostContextDev.ancestorInfo,
            type,
          );
          validateDOMNesting(null, string, ownAncestorInfo);
        }
        parentNamespace = hostContextDev.namespace;
      } else {
        parentNamespace = ((hostContext: any): HostContextProd);
      }
      // 主要在这里
      const domElement: Instance = createElement(
        type,
        props,
        rootContainerInstance,
        parentNamespace,
      );
      // 后面会进入这个方法
      precacheFiberNode(internalInstanceHandle, domElement);
      // 同上
      updateFiberProps(domElement, props);
      return domElement;
    }
    
    • 进入 createElement
      // 不展开这个方法里面调用的内容
      export function createElement(
        type: string,
        props: Object,
        rootContainerElement: Element | Document,
        parentNamespace: string,
      ): Element {
        let isCustomComponentTag;
      
        // We create tags in the namespace of their parent container, except HTML
        // tags get no namespace.
        // 先要获取 document, 先要通过 document 的api来创建
        const ownerDocument: Document = getOwnerDocumentFromRootContainer(
          rootContainerElement,
        );
        let domElement: Element;
        let namespaceURI = parentNamespace;
        // 在React中有区分,不同节点类型,都会有一个定义,比如html普通节点, svg节点等
        if (namespaceURI === HTML_NAMESPACE) {
          namespaceURI = getIntrinsicNamespace(type);
        }
        // 如果是 html 类型节点,做一些特殊处理
        if (namespaceURI === HTML_NAMESPACE) {
          if (__DEV__) {
            isCustomComponentTag = isCustomComponent(type, props);
            // Should this check be gated by parent namespace? Not sure we want to
            // allow <SVG> or <mATH>.
            warning(
              isCustomComponentTag || type === type.toLowerCase(),
              '<%s /> is using incorrect casing. ' +
                'Use PascalCase for React components, ' +
                'or lowercase for HTML elements.',
              type,
            );
          }
          // 对script节点进行特殊处理
          if (type === 'script') {
            // Create the script via .innerHTML so its "parser-inserted" flag is
            // set to true and it does not execute
            const div = ownerDocument.createElement('div');
            div.innerHTML = '<script><' + '/script>'; // eslint-disable-line
            // This is guaranteed to yield a script element.
            const firstChild = ((div.firstChild: any): HTMLScriptElement);
            domElement = div.removeChild(firstChild);
          } else if (typeof props.is === 'string') {
            // $FlowIssue `createElement` should be updated for Web Components
            domElement = ownerDocument.createElement(type, {is: props.is});
          } else {
            // Separate else branch instead of using `props.is || undefined` above because of a Firefox bug.
            // See discussion in https://github.com/facebook/react/pull/6896
            // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240
            domElement = ownerDocument.createElement(type);
            // Normally attributes are assigned in `setInitialDOMProperties`, however the `multiple`
            // attribute on `select`s needs to be added before `option`s are inserted. This prevents
            // a bug where the `select` does not scroll to the correct option because singular
            // `select` elements automatically pick the first item.
            // See https://github.com/facebook/react/issues/13222
            if (type === 'select' && props.multiple) {
              const node = ((domElement: any): HTMLSelectElement);
              node.multiple = true;
            }
          }
        } else {
          domElement = ownerDocument.createElementNS(namespaceURI, type);
        }
      
        if (__DEV__) {
          if (namespaceURI === HTML_NAMESPACE) {
            if (
              !isCustomComponentTag &&
              Object.prototype.toString.call(domElement) ===
                '[object HTMLUnknownElement]' &&
              !Object.prototype.hasOwnProperty.call(warnedUnknownTags, type)
            ) {
              warnedUnknownTags[type] = true;
              warning(
                false,
                'The tag <%s> is unrecognized in this browser. ' +
                  'If you meant to render a React component, start its name with ' +
                  'an uppercase letter.',
                type,
              );
            }
          }
        }
      
        return domElement;
      }
      
    • 进入 precacheFiberNode
      const internalInstanceKey = '__reactInternalInstance$' + randomKey;
      
      // 就是在node上挂载上述属性
      // hostInst, node 对应着 internalInstanceHandle, domElement
      // 相当于在 对应dom节点上,通过 internalInstanceKey 这个 key
      // 去创建一个指向 fiber 对象的引用
      // 后期,我们想要从dom对象上获取对应的 fiber就可以方便获取
      export function precacheFiberNode(hostInst, node) {
        node[internalInstanceKey] = hostInst;
      }
      
    • 进入 updateFiberProps
      const internalEventHandlersKey = '__reactEventHandlers$' + randomKey;
      
      // 两个参数 node 和 props, 对应着 domElement, props
      // 在 domElement 上用一个key 存储 props
      // props 会对应到上面 domElement 的 attribute, 所以,有对应关系,方便后期取用
      export function updateFiberProps(node, props) {
        node[internalEventHandlersKey] = props;
      }
      
  • 进入 appendAllChildren
    appendAllChildren = function(
      parent: Instance,
      workInProgress: Fiber,
      needsVisibilityToggle: boolean,
      isHidden: boolean,
    ) {
      // We only have the top Fiber that was created but we need recurse down its
      // children to find all the terminal nodes.
      let node = workInProgress.child;
      // 这个循环的意义:对当前节点下寻找第一层的dom节点或text节点,不会append 嵌套(继续下一层)的dom节点
      // 这样做的原因,因为对每个dom节点都会有这样一个执行 completeWork 的阶段
      // 也就是当前层只找自己下一层的dom或text, 一层一层的向下找,不会存在忽略的问题
      while (node !== null) {
        if (node.tag === HostComponent || node.tag === HostText) {
          // 注意这里,挂载节点 
          // parent 是刚刚创建的 instance
          // node.stateNode 是当前节点子节点对应的Fiber对象
          // 如果说,它的子节点那一层上面发现了原生dom节点或者文本节点,就把它挂载到节点上面
          appendInitialChild(parent, node.stateNode);
        } else if (node.tag === HostPortal) {
          // If we have a portal child, then we don't want to traverse
          // down its children. Instead, we'll get insertions from each child in
          // the portal directly.
        } else if (node.child !== null) {
          // 向下遍历
          node.child.return = node;
          node = node.child;
          continue;
        }
        // 这里直接 return
        if (node === workInProgress) {
          return;
        }
        // 没有兄弟节点,向上遍历
        while (node.sibling === null) {
          if (node.return === null || node.return === workInProgress) {
            return;
          }
          node = node.return;
        }
        // 这个本来如此,对sibling进行挂载操作
        node.sibling.return = node.return;
        // 循环找 sibling 节点
        node = node.sibling;
      }
    };
    
    • 进入 appendInitialChild
      // 这个函数执行的就是 dom 节点的 appendChild方法
      export function appendInitialChild(
        parentInstance: Instance,
        child: Instance | TextInstance,
      ): void {
        parentInstance.appendChild(child);
      }
      
  • 进入 finalizeInitialChildren
    export function finalizeInitialChildren(
      domElement: Instance,
      type: string,
      props: Props,
      rootContainerInstance: Container,
      hostContext: HostContext,
    ): boolean {
      // 做了初始化事件监听,对创建的节点根据 props 设置对应的 attribute 的封装
      setInitialProperties(domElement, type, props, rootContainerInstance);
      // 返回该节点是否需要 autoFocus
      return shouldAutoFocusHostComponent(type, props);
    }
    
    • 进入 setInitialProperties
      export function setInitialProperties(
        domElement: Element,
        tag: string,
        rawProps: Object,
        rootContainerElement: Element | Document,
      ): void {
        const isCustomComponentTag = isCustomComponent(tag, rawProps);
        if (__DEV__) {
          validatePropertiesInDevelopment(tag, rawProps);
          if (
            isCustomComponentTag &&
            !didWarnShadyDOM &&
            (domElement: any).shadyRoot
          ) {
            warning(
              false,
              '%s is using shady DOM. Using shady DOM with React can ' +
                'cause things to break subtly.',
              getCurrentFiberOwnerNameInDevOrNull() || 'A component',
            );
            didWarnShadyDOM = true;
          }
        }
      
        // TODO: Make sure that we check isMounted before firing any of these events.
        let props: Object;
        // 看下面的 switch 大部分都是绑定事件
        // 大部分都是绑定事件,这个叫做 trapBubbledEvent ,这个方法就是用来绑定事件的
        // react它有一个自己开发的事件体系,它是在dom的事件体系上面去包装了一层
        // 比如说他这边传入了这个 TOP_LOAD 
        // 它有一些事件类型,它会区分不同的一些事件类型来进行一个不同的事件绑定的方式,然后会有很多的事件的一个依赖关系
        // 可以看到这边有各种各样的不同的事件绑定。比如说 TOP_ERROR, TOP_TOGGLE, TOP_INVALID, TOP_SUBMIT
        // 对于input标签,option,select,taxtarea 都会调用对应的处理程序,如 ReactDOMInput, ReactDOMTextarea等
        // 它们都有一定的封装,因为对于这些,我们认为它是一个交互组件,就是我们要进行一些输入用户操作的一些组件
        // 比如说,input它调用的这个方法叫做 ReactDOMInput.initWrapperState 这个方法
        switch (tag) {
          case 'iframe':
          case 'object':
            trapBubbledEvent(TOP_LOAD, domElement);
            props = rawProps;
            break;
          case 'video':
          case 'audio':
            // Create listener for each media event
            for (let i = 0; i < mediaEventTypes.length; i++) {
              trapBubbledEvent(mediaEventTypes[i], domElement);
            }
            props = rawProps;
            break;
          case 'source':
            trapBubbledEvent(TOP_ERROR, domElement);
            props = rawProps;
            break;
          case 'img':
          case 'image':
          case 'link':
            trapBubbledEvent(TOP_ERROR, domElement);
            trapBubbledEvent(TOP_LOAD, domElement);
            props = rawProps;
            break;
          case 'form':
            trapBubbledEvent(TOP_RESET, domElement);
            trapBubbledEvent(TOP_SUBMIT, domElement);
            props = rawProps;
            break;
          case 'details':
            trapBubbledEvent(TOP_TOGGLE, domElement);
            props = rawProps;
            break;
          case 'input':
            ReactDOMInput.initWrapperState(domElement, rawProps);
            props = ReactDOMInput.getHostProps(domElement, rawProps);
            trapBubbledEvent(TOP_INVALID, domElement);
            // For controlled components we always need to ensure we're listening
            // to onChange. Even if there is no listener.
            ensureListeningTo(rootContainerElement, 'onChange');
            break;
          case 'option':
            ReactDOMOption.validateProps(domElement, rawProps);
            props = ReactDOMOption.getHostProps(domElement, rawProps);
            break;
          case 'select':
            ReactDOMSelect.initWrapperState(domElement, rawProps);
            props = ReactDOMSelect.getHostProps(domElement, rawProps);
            trapBubbledEvent(TOP_INVALID, domElement);
            // For controlled components we always need to ensure we're listening
            // to onChange. Even if there is no listener.
            ensureListeningTo(rootContainerElement, 'onChange');
            break;
          case 'textarea':
            ReactDOMTextarea.initWrapperState(domElement, rawProps);
            props = ReactDOMTextarea.getHostProps(domElement, rawProps);
            trapBubbledEvent(TOP_INVALID, domElement);
            // For controlled components we always need to ensure we're listening
            // to onChange. Even if there is no listener.
            ensureListeningTo(rootContainerElement, 'onChange');
            break;
          default:
            props = rawProps;
        }
      
        // 验证 props 并给出提醒
        assertValidProps(tag, props);
      
        // 初始化dom的属性相关逻辑
        setInitialDOMProperties(
          tag,
          domElement,
          rootContainerElement,
          props,
          isCustomComponentTag,
        );
      
        switch (tag) {
          case 'input':
            // TODO: Make sure we check if this is still unmounted or do any clean
            // up necessary since we never stop tracking anymore.
            inputValueTracking.track((domElement: any));
            ReactDOMInput.postMountWrapper(domElement, rawProps, false);
            break;
          case 'textarea':
            // TODO: Make sure we check if this is still unmounted or do any clean
            // up necessary since we never stop tracking anymore.
            inputValueTracking.track((domElement: any));
            ReactDOMTextarea.postMountWrapper(domElement, rawProps);
            break;
          case 'option':
            ReactDOMOption.postMountWrapper(domElement, rawProps);
            break;
          case 'select':
            ReactDOMSelect.postMountWrapper(domElement, rawProps);
            break;
          default:
            if (typeof props.onClick === 'function') {
              // TODO: This cast may not be sound for SVG, MathML or custom elements.
              trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
            }
            break;
        }
      }
      
      • 进入 ReactDOMInput.initWrapperState
        // packages/react-dom/src/client/ReactDOMInput.js
        export function initWrapperState(element: Element, props: Object) {
          // 跳过 DEV
          if (__DEV__) {
            ReactControlledValuePropTypes.checkPropTypes('input', props);
        
            if (
              props.checked !== undefined &&
              props.defaultChecked !== undefined &&
              !didWarnCheckedDefaultChecked
            ) {
              warning(
                false,
                '%s contains an input of type %s with both checked and defaultChecked props. ' +
                  'Input elements must be either controlled or uncontrolled ' +
                  '(specify either the checked prop, or the defaultChecked prop, but not ' +
                  'both). Decide between using a controlled or uncontrolled input ' +
                  'element and remove one of these props. More info: ' +
                  'https://fb.me/react-controlled-components',
                getCurrentFiberOwnerNameInDevOrNull() || 'A component',
                props.type,
              );
              didWarnCheckedDefaultChecked = true;
            }
            if (
              props.value !== undefined &&
              props.defaultValue !== undefined &&
              !didWarnValueDefaultValue
            ) {
              warning(
                false,
                '%s contains an input of type %s with both value and defaultValue props. ' +
                  'Input elements must be either controlled or uncontrolled ' +
                  '(specify either the value prop, or the defaultValue prop, but not ' +
                  'both). Decide between using a controlled or uncontrolled input ' +
                  'element and remove one of these props. More info: ' +
                  'https://fb.me/react-controlled-components',
                getCurrentFiberOwnerNameInDevOrNull() || 'A component',
                props.type,
              );
              didWarnValueDefaultValue = true;
            }
          }
        
        
          const node = ((element: any): InputWithWrapperState);
        
          // 关于 defaultValue, 如果不希望使用value来绑定input它的一个值
          // 如果绑定了value这个值,我们input的value,只能通过 setState 这个value的值来进行一个变更
          // 如果我们没有绑定事件,那么我们在input里面输入是不会有任何变化的
          // 那这个时候我们如果要有初始的值,又不希望去绑定 value
          // 可以通过使用 defaultValue,如果没有 defaultvalue 它就是一个空的
          const defaultValue = props.defaultValue == null ? '' : props.defaultValue;
        
          // 在input对应的dom节点上面呢去挂载了一个属性,叫做 _wrapperState
          // 它里面定义了3个属性
          node._wrapperState = {
            initialChecked:
              props.checked != null ? props.checked : props.defaultChecked,
            initialValue: getToStringValue(
              props.value != null ? props.value : defaultValue,
            ),
            controlled: isControlled(props),
          };
        }
        
        • 进入 isControlled
          // 处理 checkbox 和 radio
          function isControlled(props) {
            const usesChecked = props.type === 'checkbox' || props.type === 'radio';
            return usesChecked ? props.checked != null : props.value != null;
          }
          
      • 进入 getHostProps
        export function getHostProps(element: Element, props: Object) {
          const node = ((element: any): InputWithWrapperState);
          const checked = props.checked;
          // 组合 props
          const hostProps = Object.assign({}, props, {
            defaultChecked: undefined,
            defaultValue: undefined,
            value: undefined,
            checked: checked != null ? checked : node._wrapperState.initialChecked,
          });
        
          return hostProps;
        }
        
      • 对于 assertValidPropssetInitialDOMProperties
        • 这样两项封装的Dom操作细节处理,不展开
        • 前者做提示处理,后者做dom操作
    • 进入 shouldAutoFocusHostComponent
      function shouldAutoFocusHostComponent(type: string, props: Props): boolean {
        // 对可以 focus 的 dom节点进行 bool 处理,注意,这里没有 break
        switch (type) {
          case 'button':
          case 'input':
          case 'select':
          case 'textarea':
            return !!props.autoFocus;
        }
        return false;
      }
      
  • 进入 markUpdate
    // 标记 Update 这个 SideEffect
    function markUpdate(workInProgress: Fiber) {
      // Tag the fiber with an update effect. This turns a Placement into
      // a PlacementAndUpdate.
      workInProgress.effectTag |= Update;
    }
    
  • 关于 更新时的 updateHostComponent 这块后续单独拿出来说

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

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

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

相关文章

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

    beginWork 1 )概述 在 renderRoot 之后,要对我们的 Fiber 树每一个节点进行对应的更新 更新节点的一个入口方法,就是 beginWork 这个入口方法会有帮助我们去优化整棵树的更新过程 react 它的节点其实是非常多的,如果每一次子节点的一个更新 就需要每一个节点都执行一遍更新的话

    2024年01月20日
    浏览(47)
  • React16源码: React中的IndeterminateComponent的源码实现

    IndeterminateComponent 1 )概述 这是一个比较特殊的component的类型, 就是还没有被指定类型的component 在一个fibrer被创建的时候,它的tag可能会是 IndeterminateComponent 在 packages/react-reconciler/src/ReactFiber.js 中,有一个方法 createFiberFromTypeAndProps 中,一开始就声明了 在最终调用 createFibe

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

    reconcileChildren 1 )概述 在更新了一个节点之后,拿到它的props.children 要根据这个children里面的 ReactElement 来去创建子树的所有的 fiber 对象 要根据 props.children 来生成 fiber 子树,然后判断 fiber 对象它是否是可以复用的 因为我们在第一次渲染的时候,就已经渲染了整个 fiber 子树

    2024年01月20日
    浏览(41)
  • React16源码: React中的performWork的源码实现

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

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

    unwindWork 1 )概述 在 renderRoot 的 throw Exception 里面, 对于被捕获到错误的组件进行了一些处理 并且向上去寻找能够处理这些异常的组件,比如说 class component 里面具有 getDerivedStateFromError 或者 componentDidCatch 这样的生命周期方法 这个class component 就代表它可以处理它的子树当中渲

    2024年01月25日
    浏览(37)
  • 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日
    浏览(40)
  • React16源码: React中的completeUnitOfWork的源码实现

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

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

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

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

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

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

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

    2024年02月01日
    浏览(39)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包