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

HostComponent


1 )概述

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

2 )源码

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

找到 case HostComponent

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的事件体系
        finalizeInitialChildren(
          instance,
          type,
          newProps,
          rootContainerInstance,
          currentHostContext,
        )
      ) {
        markUpdate(workInProgress);
      }
      workInProgress.stateNode = 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  or .
          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 = '
                        
                        

你可能感兴趣的:(React,React,Native,react.js,前端,前端框架)