博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React 源码深度解读(三):首次 DOM 元素渲染 - Part 3
阅读量:6255 次
发布时间:2019-06-22

本文共 4077 字,大约阅读时间需要 13 分钟。

  • 前言

React 是一个十分庞大的库,由于要同时考虑 ReactDom 和 ReactNative ,还有服务器渲染等,导致其代码抽象化程度很高,嵌套层级非常深,阅读其源码是一个非常艰辛的过程。在学习 React 源码的过程中,给我帮助最大的就是,于是决定基于这个系列文章谈一下自己的理解。本文会大量用到原文中的例子,想体会原汁原味的感觉,推荐阅读原文。

本系列文章基于 React 15.4.2 ,以下是本系列其它文章的传送门:

  • 正文

上一篇讲解了平台无关的代码,这篇继续来讲针对与 HTML DOM 操作的代码。

|=ReactMount.render(nextElement, container, callback)     ___|=ReactMount._renderSubtreeIntoContainer()                 |  |-ReactMount._renderNewRootComponent()                   |    |-instantiateReactComponent()                          |    |~batchedMountComponentIntoNode()                  upper half      |~mountComponentIntoNode()                       (平台无关)        |-ReactReconciler.mountComponent()                 |          |-ReactCompositeComponent.mountComponent()       |          |-ReactCompositeComponent.performInitialMount()  |            |-instantiateReactComponent()                 _|_            |-ReactDOMComponent.mountComponent()       lower half        |-_mountImageIntoNode()                      (HTML DOM 相关)                                                          _|_

先来看看 ReactDOMComponent.mountComponent 做了什么:

// 文件位置:src/renderers/dom/shared/ReactDomComponent.jstComponent: function (    transaction,    hostParent,    hostContainerInfo,    context) {    ...    var mountImage;        var ownerDocument = hostContainerInfo._ownerDocument;    var el;        // document.createElement 创建 h1 元素    el = ownerDocument.createElement(this._currentElement                .type, props.is);    ...      // 创建 component 与 DOM 的双向链接    // ReactDOMComponent[ins]._hostNode 指向 DOM    // DOM 的 __reactInternalInstance 指向 component    ReactDOMComponentTree.precacheNode(this, el);        // 设置属性    this._updateDOMProperties(null, props, transaction);        var lazyTree = DOMLazyTree(el);        // 循环创建子元素    this._createInitialChildren(transaction, props, context,        lazyTree);            mountImage = lazyTree;    ...    return mountImage;},

到此为止,实例间的关系是这样的:

clipboard.png

DOM 元素创建完成后,剩下的就是将其挂载到 container 上面去了。这里调用的是 ReactMount 的 _mountImageIntoNode:

|=ReactMount.render(nextElement, container, callback)     ___|=ReactMount._renderSubtreeIntoContainer()                 |  |-ReactMount._renderNewRootComponent()                   |    |-instantiateReactComponent()                          |    |~batchedMountComponentIntoNode()                  upper half      |~mountComponentIntoNode(                        (平台无关)          wrapperInstance, // scr: -> not of interest now  |          container,   // scr: --> document.getElementById(‘root’)          transaction, // scr: --> not of interest         |          shouldReuseMarkup, // scr: -------> null         |          context,           // scr: -------> not of interest        )                                                  |        |-ReactReconciler.mountComponent()                 |          |-ReactCompositeComponent.mountComponent()       |          |-ReactCompositeComponent.performInitialMount()  |            |-instantiateReactComponent()                 _|_            |-ReactDOMComponent.mountComponent()           |       /* we are here */                               lower half        |-_mountImageIntoNode()                      (HTML DOM 相关)            markup,    // scr: --> DOMLazyTree[ins]        |            container, // scr: --> document.getElementById(‘root’)            wrapperInstance, // scr:----> same             |            shouldReuseMarkup, // scr:--> same             |            transaction, // scr: -------> same             |          )

具体实现:

_mountImageIntoNode: function (        markup,        // DOMLazyTree[ins]         container,     // document.getElementById(‘root’)        instance,        shouldReuseMarkup,        transaction    ) {        ...                while (container.lastChild) {            container.removeChild(container.lastChild);        }                DOMLazyTree.insertTreeBefore(container, markup, null);        ...    }

DOMLazyTree.insertTreeBefore 最终会调用 parentNode.insertBefore,将元素挂载到 container 上。到此为止,首次渲染就完成啦!

  • 总结

从 React 启动到元素渲染到页面,并不像看起来这么简单,中间经历了复杂的层级调用。原文的这张图总结得非常好:

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

转载地址:http://izfsa.baihongyu.com/

你可能感兴趣的文章
LINUX总结
查看>>
编译php5.4的时候出现错误----configure: error: in `/usr/local/src/php540/php-5.4.0':
查看>>
机器学习编程01_线性回归
查看>>
Markdown语法
查看>>
《CSS世界》读书笔记(十六)
查看>>
初入前端
查看>>
(回文串 )Best Reward -- hdu -- 3613
查看>>
最少拦截系统------LCS--------动态规划
查看>>
关于EOF的种种。
查看>>
h5 拍照上传 代码
查看>>
javascript 通用定义
查看>>
语文文法
查看>>
SSM(Spring,SpringMVC,MyBatis)用户登录
查看>>
关于SQL注入,你应该知道的那些事
查看>>
jquery bxslider幻灯片样式改造
查看>>
常用JavaScript操作页面元素的方法
查看>>
学习进度条 12/18 到12/23
查看>>
varnish学习以及CDN的原理
查看>>
服务器配置 隐藏apache和php的版本
查看>>
将数据表中的数据导出到Excel、将Excel中的数据导入到数据表
查看>>