阅读 693

React渲染 - 流程概述

导语 web前端技术中,有个叫做jsx的模板渲染语法,它是一个JavaScript 的语法扩展,目前逐渐被行业标准化(用的人多了...)。实际上jsx 是来源于一个前端框架 react。在react中除了我们了解的jsx,那么jsx在react的渲染过程是哪个环节生效,以及渲染过程经历了哪些步骤。本文会基于这些点进行概述。

介绍前的建议

1.本文附上了react.render树状图.xmind,此为作者查看/调试react的渲染源码时做的结构笔记。可以下载进行一些函数定位,一些函数代码位置较深且存在部分依赖,以此关联上下文是个不错的选择。

2.作者是基于17版本的react进行解读与调试 -- github.com/facebook/re…

3.设置了几个大标题,提前介绍一下有关react的函数,二、三 目录可直接跳过。

React中用到的一些Object设置对象属性方法

React中自带的常用方法

React中的常用名词

jsx简述

比如如下代码:

ReactDOM.render(
<div>
<h1>Hello, world!</h1>
<p>React to Render</p>
</div>
,
document.getElementById('root')
);
复制代码

这样就简单完成了页面的渲染。这其中经历了:

1.jsx经过babel打包转换成js语法 (@babel/helper-builder-react-jsx-experimental)

2.react执行render函数,进行节点的遍历渲染并绑定事件

如果拿刚才上述的代码进行babel转换,那么可以得到如下具体执行的jscode:

ReactDOM.render( 
    /*#__PURE__*/
    React.createElement("div",
    null, 
    /*#__PURE__*/
    React.createElement("h1", null, "Hello, world!"),
    /*#__PURE__*/ 
    React.createElement("p", null, "React to Render")), 
    document.getElementById('root')
 );
复制代码

附上一个在线jsx转换地址: babeljs.io/repl/

如果同学们需要了解具体的转换语法,可以从 @babel/preset-react 中入口寻找依赖,具体的实现在 @babel/helper-builder-react-jsx-experimental、@babel/helper-plugin-utils

作者仅简单关联了上下文,这里稍作截图:

我们会在webpack打包后的代码中看到 "_source","jsxFileName" 关键字。

这里的@babel/helper-plugin-utils还有一个作用:dev环境时在打包过程中 输出文件代码块的位置,以便于调试定位,处理会返回输出的一个只读属性 "__source",其中包含 { fileName:path, lineNumber:number, columnNumber:number }

所以,jsx语法与渲染的执行代码没有存在关联,react通过babel转换成原生js进行处理执行。转换后的createElement即为创建节点。

创建节点

创建节点的入口代码在 "react/src/React.js" createElement函数

createElement会根据当前的环境,引用不同的创建函数

图片

不过,开发版与产品版仅是一些有没有验证合法性,和是否输出错误内容的区别。最终都会创建同样的element对象 -- 虚拟节点

如下图所示:

图片

图上面右侧的错误提示中,用到的

图片

"filename,lineNumber"即在打包过程中 @babel/helper-plugin-utils 提前注入好对象属性

当执行 真正的创建节点时 "ReactElement.js/createElement",这里会生成一个带有一些标记属性的Node对象:

图片

渲染

渲染可以按照功能,切分为三个点 准备、执行、提交。

render函数在 "/react-dom/src/client/ReactDOMLegacy.js"中,在进行一系列检查判断后最终会在legacyRenderSubtreeIntoContainer函数下执行渲染

legacyRenderSubtreeIntoContainer函数会执行以下三个步骤 :

图片

代码大致截图:

图片

我们按照3个步骤往下延伸:

1-准备阶段:

做两件事:

1.创建根节点的一些关联对象 ReactRoot、fiberRoot、(HostRoot)fiberNode

2.定义根节点的默认浏览器事件

如下图,此为根节点(root)的关联对象

图片

关联对象具备如下一些属性及功能

图片

如下图,定义的默认事件:

图片

准备阶段总结如下:

图片

2 - 执行阶段 :

代码入口在 "react-reconciler/src/ReactFiberReconciler.js" unbatchedUpdates函数中

此阶段给所有的节点生成好节点树,等待提交

如下图所示:

图片

3 - 提交阶段:

提交阶段的代码也在 "react-reconciler/src/ReactFiberReconciler.js" unbatchedUpdates函数内执行

具体的函数执行在 "react-reconciler/src/ReactFiberWorkLoop.new.js" performSyncWorkOnRoot函数下执行 commitRoot

进行实际的执行Dom操作、部分周期函数

如下图所示:

图片

最终在 commitBeforeMutationEffects 和 commitMutationEffects 执行真正的dom操作和事件提交

整体的渲染流程到提交阶段执行完之后页面就已经能够看到效果,剩下的动作做一些数据同步、重设标记时间等..

图片

原作者: 陈碧松

未经同意,禁止转载!

更多精彩内容,尽请关注腾讯VTeam技术团队微信公众号和视频号

文章分类
前端
文章标签