React 源码解析- render 入口篇

render() 方法是 react 应用的入口方法,所有的 jsx 渲染 hooks 挂载和执行等,都在这个里面,本文将会通过一个小小的案例,来进行讲解。


举个🌰

js 复制代码
const root = ReactDOM.createRoot(document.getElementById('root'));  
root.render(  
    <App />  
);

function App() {  
    return (  
    <section>hello</section>  
);  
}

ReactDOM.createRoot

①处的标记,isValidContainer 判断传入的 dom 节点是否是 合法的挂载对象

如普通的 element 节点,document 节点,文档片段节点等,都是合法的挂载对象。NodeType 属性详见MDN Node:nodeType 属性

②处的标记,warnIfReactDOMContainerInDEV 判断,若 container 作为 body 或已经被作为 root 使用过,则在 dev 环境发出警告,④处的标记,markContainerAsRoot 则对 container 进行标记为 root 节点,如果再次使用,则发出警告

这里我们把 warnIfReactDOMContainerInDEVmarkContainerAsRoot 结合起来看,markContainerAsRoot 先是给 node 添加一个 internalContainerInstanceKey 属性,然后在 warnIfReactDOMContainerInDEV 中判断是否有此属性,如果有,则是已经被作为 root 使用过,则在 dev 环境发出警告。

③处的标记,调用 createContainer 创建一个 FiberRoot 类型的节点;

createContainer 代码如下:

下面我们继续看createFiberRoot

其实就是调用 FiberRootNode 赋值给 root, 最后返回给上层调用函数

⑤处的标记,listenToAllSupportedEvents 主要是挂载事件

⑥处的标记,new ReactDOMRoot 主要是返回一个 ReactDOMRoot 的实例,render() 方法就是这个类的一个实例

new ReactDOMRoot 传入的参数就是在 createContainer 创建的 FiberRoot ,即 root(FiberRootNode 是整个应用的根节点 ),在 ReactDOMRoot 构造函数种赋值给 this._internalRoot

至此 createRoot 方法大致流程已经分析完了,其实主要就是创建整个应用的根节点 FiberRootNode,以及创建 所在组件树的根节点 FiberNode。

ReactDOMRoot

ReactDOMRoot 的实现很简单,就是将创建的 FiberRootNode 类型的节点放在实例的 _internalRoot 属性上。然后在 ReactDOMRoot 的原型链上添加 renderunmount 两个方法。

  • 在 render 方法中,获取 root 值,然后调用 updateContainer 进行更新;
  • 在 unmount 方法中,把 _internalRoot 清空,然后调用 unmarkContainerAsRoot,取消标记,这里和 createRoot 中的 warnIfReactDOMContainerInDEVmarkContainerAsRoot 前后相呼应起来。
js 复制代码
export function unmarkContainerAsRoot(node: Container): void {
  node[internalContainerInstanceKey] = null;
}

render

执行完 ReactDOM.createRoot 后将会执行 root.render(<App />) ,下面我们先来看下源码,如图:

其实就是在 ReactDOMRoot.prototype 上挂了个 render 函数,主要也就是两行代码:

  • 标记 ① 处就是把在 createRoot 中 赋值的 _internalRoot 变量赋值给 root 变量;
  • 标记 ② 处调用了 updateContainer 函数,我们接下来将会主要分析这个函数。

下面我们主要分析一下 updateContainer 这个函数。

  1. const current = container.current 获取 FiberRootNode.current 现在指向到当前的 fiber 树,若是初次执行,current 树只有 hostFiber 节点,没有其他的;

  2. const lane = requestUpdateLane(current), requestUpdateLane 创建了 lane,获取工作的优先级;

  3. const update = createUpdate(lane),这里结合 lane 优先级,创建 update 对象,,一个 update 对象意味着一个更新;

  4. update.payload = {element}, 可以看到,把 element (react 的 ReactNodeList)当做荷载放到了 update 里面去了;

  5. const root = enqueueUpdate(current, update, lane),创建 update 对象入队,后续会继续讲解这部分流程;

  6. scheduleUpdateOnFiber(root, current, lane) 这个方法中牵涉到的逻辑也是比较多,由于篇幅问题,会在后续进行详细讲解。

入口方法 render() 我们就大致讲到这里,不过还有很多只是粗略的提了一下,在后续的文章种会继续讲讲解。

相关推荐
css趣多多4 分钟前
this.$watch
前端·javascript·vue.js
●VON11 分钟前
React Native for OpenHarmony:ScrollView 事件流、布局行为与性能优化深度剖析
学习·react native·react.js·性能优化·openharmony
干前端25 分钟前
Vue3虚拟滚动列表组件进阶:不定高度及原理分析!!!
前端·前端组件
雨季66631 分钟前
Flutter 三端应用实战:OpenHarmony “极简文本行数统计器”
开发语言·前端·flutter·ui·交互
2601_9495936539 分钟前
高级进阶 React Native 鸿蒙跨平台开发:LinearGradient 玻璃拟态卡片
react native·react.js·harmonyos
MAHATMA玛哈特科技44 分钟前
以曲求直:校平技术中的反直觉哲学
前端·数据库·制造·校平机·矫平机·液压矫平机
C澒1 小时前
前端技术核心领域与实践方向
前端·系统架构
摘星编程1 小时前
在OpenHarmony上用React Native:TopTab顶部标签页
react native·react.js·harmonyos
写代码的【黑咖啡】1 小时前
Python 中的自然语言处理利器:NLTK
前端·javascript·easyui
Swift社区1 小时前
Nginx 反向代理配置 React 前端与 Python 后端
前端·nginx·react.js