react源码分析:组件的创建和更新

这一章节就来讲讲ReactDOM.render()方法的内部实现与流程吧。
因为初始化的源码文件部分所涵盖的内容很多,包括创建渲染更新渲染Fiber树的创建与diffelement的创建与插入,还包括一些优化算法,所以我就整个的React执行流程画了一个简单的示意图。

React源码执行流程图

在这里插入图片描述

从图中我们很清晰的看到ReactDOM.render()之后我们的组件具体干了什么事情,那么我们进入源码文件一探究竟吧。

// packages/react-dom/src/client/ReactDOMLegacy.js
export function render(
  element: React$Element<any>, // 经过babel解析后的element
  container: Container, // 根组件节点: document.getElementById('root')..
  callback: ?Function,// 回调
) {
   
  // 做合法容器的验证(根组件)
  invariant(
    isValidContainer(container),
    'Target container is not a DOM element.',
  );

  // 开发模式下
  if (__DEV__) {
   
    const isModernRoot =
      isContainerMarkedAsRoot(container) &&
      container._reactRootContainer === undefined;
    if (isModernRoot) {
   
      console.error(
        'You are calling ReactDOM.render() on a container that was previously ' +
          'passed to ReactDOM.createRoot(). This is not supported. ' +
          'Did you mean to call root.render(element)?',
      );
    }
  }
  // 返回 legacyRenderSubtreeIntoContainer
  return legacyRenderSubtreeIntoContainer(
    null,
    element,
    container,
    false,
    callback,
  );
}

所以当前render函数仅仅只是做了部分逻辑,阅读React源码,给你一个直观的感受就是他拆分的颗粒度非常的细,很多重复命名的函数,可能是见名知意的变量名只有那么几个常见的组合吧,这也是React作者的用心良苦吧。

追根究底我们还是得看一看legacyRenderSubtreeIntoContainer究竟干了些不为人知的事情呢

legacyRenderSubtreeIntoContainer

function legacyRenderSubtreeIntoContainer(
  parentComponent: ?React$Component<any, any>, // 父级组件
  children: ReactNodeList, // 当前元素
  container: Container, // 容器 eg:getElementById('root')
  forceHydrate: boolean,  callback: ?Function,
) {
   
  if (__DEV__) {
   
    topLevelUpdateWarnings(container);
    warnOnInvalidCallback(callback === undefined ? null : callback, 'render');
  }

  // TODO: Without `any` type, Flow says "Property cannot be accessed on any
  // member of intersection type." Whyyyyyy.
  let root: RootType = (container._reactRootContainer: any);
  let fiberRoot;
  // 如果有根组件,表示不是初始化渲染,则走下面的批量更新
  // 没有根组件,那么就要去创建根组件了
  if (!root) {
   
    // 初始化挂载
    root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
      container,
      forceHydrate,
    );
    fiberRoot = root._internalRoot;
    if (typeof callback === 'function') {
   
      const originalCallback = callback;
      callback = function() {
   
        const instance = getPublicRootInstance(fiberRoot);
        originalCallback.call(instance);
      };
    }
    // 不必要的批量更新
    unbatchedUpdates(() => {
   
      updateContainer(children, fiberRoot, parentComponent, callback);
    });
  } else {
   
    fiberRoot = root._internalRoot;
    if (typeof callback === 'function') {
   
      const originalCallback = callback;
      callback = function() {
   
        const instance = getPublicRootInstance(fiberRoot);
        originalCallback.call(instance);
      };
    }
    // 批量更新
    updateContainer(children, fiberRoot, parentComponent, callback);
  }
  return getPublicRootInstance(fiberRoot);
}
  • 有根节点的情况下,我们判定为非首次渲染状态,执行updateContainer
  • 没有根节点的情况下,我们判定为首次渲染,接着去创建根节点,执行legacyCreateRootFromDOMContainer,拿到了root之后,我们会去触发执行updateContainer

legacyCreateRootFromDOMContainer

function legacyCreateRootFromDOMContainer(
  container: Container, // 容器
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值