一、ReactDOM.render

创建ReactRoot,并且根据情况调用root.legacy_renderSubtreeIntoContainer或者root.render,前者是遗留的 API 将来应该会删除,根据ReactDOM.render的调用情况也可以发现parentComponent是写死的null

DOMRenderer.unbatchedUpdates制定不使用batchedUpdates,因为这是初次渲染,需要尽快完成。

  hydrate(element: React$Node, container: DOMContainer, callback: ?Function) {
// TODO: throw or warn if we couldn't hydrate?
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
true,
callback,
);
}, render(
element: React$Element<any>,
container: DOMContainer,
callback: ?Function,
) {
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
},

  

function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
container: DOMContainer,
forceHydrate: boolean,
callback: ?Function,
) {
let root: Root = (container._reactRootContainer: any);
if (!root) {
// Initial mount
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
const instance = DOMRenderer.getPublicRootInstance(root._internalRoot);
originalCallback.call(instance);
};
}
// Initial mount should not be batched.
DOMRenderer.unbatchedUpdates(() => {
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(
parentComponent,
children,
callback,
);
} else {
root.render(children, callback);
}
});
} else {
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
const instance = DOMRenderer.getPublicRootInstance(root._internalRoot);
originalCallback.call(instance);
};
}
// Update
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(
parentComponent,
children,
callback,
);
} else {
root.render(children, callback);
}
}
return DOMRenderer.getPublicRootInstance(root._internalRoot);
}

首先会创建ReactRoot对象,然后调用他的render方法

创建ReactRoot的时候会调用DOMRenderer.createContainer创建FiberRoot,在后期调度更新的过程中这个节点非常重要

function legacyCreateRootFromDOMContainer(
container: DOMContainer,
forceHydrate: boolean,
): Root {
const shouldHydrate =
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// First clear any existing content.
if (!shouldHydrate) {
let warned = false;
let rootSibling;
while ((rootSibling = container.lastChild)) {
if (__DEV__) {
if (
!warned &&
rootSibling.nodeType === ELEMENT_NODE &&
(rootSibling: any).hasAttribute(ROOT_ATTRIBUTE_NAME)
) {
warned = true;
warningWithoutStack(
false,
'render(): Target node has markup rendered by React, but there ' +
'are unrelated nodes as well. This is most commonly caused by ' +
'white-space inserted around server-rendered markup.',
);
}
}
container.removeChild(rootSibling);
}
}
if (__DEV__) {
if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) {
warnedAboutHydrateAPI = true;
lowPriorityWarning(
false,
'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
'will stop working in React v17. Replace the ReactDOM.render() call ' +
'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
);
}
}
// Legacy roots are not async by default.
const isConcurrent = false;
return new ReactRoot(container, isConcurrent, shouldHydrate);
}

  

export function createContainer(
containerInfo: Container,
isConcurrent: boolean,
hydrate: boolean,
): OpaqueRoot {
return createFiberRoot(containerInfo, isConcurrent, hydrate);
}

  

二、启动调度

首先要生成一个update,不管你是setState还是ReactDOM.render造成的 React 更新,都会生成一个叫update的对象,并且会赋值给Fiber.updateQueue

然后就是调用scheduleWork。注意到这里之前setStateReactDOM.render是不一样,但进入schedulerWork之后,就是任务调度的事情了,跟之前你是怎么调用的没有任何关系

function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) {
const root = scheduleWorkToRoot(fiber, expirationTime);
if (root === null) {
return;
} if (
!isWorking &&
nextRenderExpirationTime !== NoWork &&
expirationTime < nextRenderExpirationTime
) {
// This is an interruption. (Used for performance tracking.)
interruptedBy = fiber;
resetStack();
}
markPendingPriorityLevel(root, expirationTime);
if (
// If we're in the render phase, we don't need to schedule this root
// for an update, because we'll do it before we exit...
!isWorking ||
isCommitting ||
// ...unless this is a different root than the one we're rendering.
nextRoot !== root
) {
const rootExpirationTime = root.expirationTime;
requestWork(root, rootExpirationTime);
}
if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
// Reset this back to zero so subsequent updates don't throw.
nestedUpdateCount = 0;
invariant(
false,
'Maximum update depth exceeded. This can happen when a ' +
'component repeatedly calls setState inside ' +
'componentWillUpdate or componentDidUpdate. React limits ' +
'the number of nested updates to prevent infinite loops.',
);
}
}

  

  

React源码解析——创建更新过程的更多相关文章

  1. React源码解析之React.Children.map()(五)

    一,React.Children是什么? 是为了处理this.props.children(this.props.children表示所有组件的子节点)这个属性提供的工具,是顶层的api之一 二,Re ...

  2. Fresco源码解析 - 创建一个ImagePipeline(一)

    在Fresco源码解析 - 初始化过程分析章节中, 我们分析了Fresco的初始化过程,两个initialize方法中都用到了 ImagePipelineFactory类. ImagePipeline ...

  3. React源码解析:ReactElement

    ReactElement算是React源码中比较简单的部分了,直接看源码: var ReactElement = function(type, key, ref, self, source, owne ...

  4. [Java多线程]-线程池的基本使用和部分源码解析(创建,执行原理)

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 多线 ...

  5. React源码解析:setState

    先来几个例子热热身: ......... constructor(props){ super(props); this.state = { index: 0 } } componentDidMount ...

  6. React源码解析——ReactAPI

    一.API背景 api的具体转化关系 可以通过到https://babeljs.io/repl/网站去将我们创建的Jsx进行实时的转译 const React = { Children: { map, ...

  7. React源码解析-Virtual DOM解析

    前言:最近一直在研究React,看了陈屹先生所著的深入React技术栈,以及自己使用了这么长时间.对React应该说有比较深的理解了,正好前阵子也把两本关于前端设计模式的书看完了,总感觉有一种知识错综 ...

  8. SpringBoot源码解析:创建SpringApplication对象实例

    上篇文章SpringBoot自动装配原理解析中,我们分析了SpringBoot的自动装配原理以及@SpringBootApplication注解的原理,本篇文章则继续基于上篇文章中的main方法来分析 ...

  9. React躬行记(16)——React源码分析

    React可大致分为三部分:Core.Reconciler和Renderer,在阅读源码之前,首先需要搭建测试环境,为了方便起见,本文直接采用了网友搭建好的环境,React版本是16.8.6,与最新版 ...

随机推荐

  1. Windows 10 右键 在此处打开 CMD

    1. 打开注册表 # 1. 使用快捷键打开 “运行” # win + r # 2. 在 “运行” 中输入 # regedit # 3. 回车 2. 创建与设置 OpenCMDHere # 1. 切换到 ...

  2. 爬虫(一)爬取鱼c淘贴信息

    掏出了以前的小练习: 现在开始,每天复习下以前的爬虫练习,争取发现新的问题和可以优化的地方. # -*- coding:utf-8 -*- import requests import chardet ...

  3. 7-49 求前n项的阶乘之和 (15 分)

    从键盘输入一个整数n,求前n项的阶乘之和,1+2!+3!+...+n!的和 输入格式: 输入一个大于1的整数.例如:输入20. 输出格式: 输出一个整数.例如:2561327494111820313. ...

  4. python+opencv->边缘提取与各函数参数解析

    前情提要:作为刚入门机器视觉的小伙伴,第一节课学到机器视觉语法时觉得很难理解, 很多人家的经验,我发现都千篇一律,功能函数没解析,参数不讲解,就一个代码,所以在此将搜集的解析和案例拿出来汇总!!! 一 ...

  5. Java避坑宝典《Java业务开发常见错误100例》上线了

    写这个专栏的缘起 之前我写过一篇博客:<朱晔的互联网架构实践心得S2E2:写业务代码最容易掉的10种坑>,引起的关注还是挺多的.后来和极客时间的编辑一拍即合决定以这个为题写一个专栏.其实所 ...

  6. vue环境搭建过程中,npm权限不足问题

    今天在用git bash进行全局安装vue-cli的时候,报错: 必须以管理员权限进行安装才行.所以用cmd命令工具,点击右键命令提示符cmd--------以管理员身份运行--------cd进入到 ...

  7. springmvc 的@ResponseBody 如何使用JSONP?

    JSONP解释 在解释JSONP之前,我们需要了解下”同源策略“这个概念,这对理解跨域有帮助.基于安全的原因,浏览器是存在同源策略机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载额文 ...

  8. Hadoop fs 基础命令

    操作hdfs的基本命令 在hdfs中,路径需要用绝对路径 1. 查看根目录 hadoop fs -ls / 2. 递归查看所有文件和文件夹 -lsr等同于-ls -R hadoop fs -lsr / ...

  9. 分享几个 PHP 编码的最佳实践

    对于初学者而言,可能很难理解为什么某些做法更安全. 但是,以下一些技巧可能超出了 PHP 的范围. 始终使用大括号 让我们看下面的代码: if (isset($condition) && ...

  10. java之AQS和显式锁

    本次内容主要介绍AQS.AQS的设计及使用.ReentrantLock.ReentrantReadWriteLock以及手写一个可重入独占锁 1.什么是AQS? AQS,队列同步器AbstractQu ...