我们假定你对react有一定的了解会应用react,且看过官方文档。此处使用的react和react-dom版本是:16.7.0。
使用creat-react-app创建一个App,并启动。

  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. class App extends Component {
  4. render() {
  5. return (<div id='appId'>Hello World!</div>);
  6. }
  7. }
  8. ReactDOM.render(<App />, document.getElementById('root'));

在执行这段代码时,ReactDOM.render中的会被转为:
image.png

将App换为div,修改代码为:

  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. ReactDOM.render(<div id='appId'>Hello World!</div>, document.getElementById('root'));

在执行这段代码时,ReactDOM.render中的’

Hello World!
‘会被转为:
image.png
在react的世界里,不论 div 还是 App 都是react.element,转换后的都带有各自的身份type。无论身份身份相同,初始处理的方式都相似。

ReactElement

ReactElement的格式如下:

  1. // packages\shared\ReactElementType.js
  2. export type Source = {
  3. fileName: string,
  4. lineNumber: number,
  5. };
  6. export type ReactElement = {
  7. $$typeof: any,
  8. type: any,
  9. key: any,
  10. ref: any,
  11. props: any,
  12. _owner: any, // ReactInstance or ReactFiber
  13. // __DEV__
  14. _store: {
  15. validated: boolean,
  16. },
  17. _self: React$Element<any>,
  18. _shadowChildren: any,
  19. _source: Source,
  20. };

div等 和 Component都是ReactElement,值不同而已。

Render

react-dom是react的一个渲染器。按React设计思路,react-dom是提供针对DOM的方法。

  1. var ReactDOM = {
  2. render: function render(element, container, callback) {
  3. return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
  4. }
  5. }

在调用 ReactDOM.render 时,第一个参并不是根元素。使用ReactDOM.render时,调用的是 legacyCreateRootFromDOMContainer 。在legacyCreateRootFromDOMContainer 中会根据root的有无,判断当前所在的阶段。若无 root 是Initial mount,有root则是 Update。在Initial mount阶段,legacyCreateRootFromDOMContainer 会返回 ReactRoot 实例。

  1. function legacyRenderSubtreeIntoContainer(
  2. parentComponent: ?React$Component<any, any>,
  3. children: ReactNodeList,container: DOMContainer,forceHydrate: boolean,callback: ?Function
  4. ) {
  5. let root: Root = (container._reactRootContainer: any);
  6. if (!root) {
  7. // Initial mount
  8. root = container._reactRootContainer = legacyCreateRootFromDOMContainer( container,
  9. forceHydrate,
  10. );
  11. if (typeof callback === 'function') {
  12. const originalCallback = callback;
  13. callback = function() {
  14. const instance = getPublicRootInstance(root._internalRoot);
  15. originalCallback.call(instance);
  16. };
  17. }
  18. // Initial mount should not be batched.
  19. unbatchedUpdates(() => {
  20. if (parentComponent != null) {
  21. root.legacy_renderSubtreeIntoContainer(parentComponent,children,callback);
  22. } else {
  23. root.render(children, callback);
  24. }
  25. });
  26. } else {
  27. if (typeof callback === 'function') {
  28. const originalCallback = callback;
  29. callback = function() {
  30. const instance = getPublicRootInstance(root._internalRoot);
  31. originalCallback.call(instance);
  32. };
  33. }
  34. // Update
  35. if (parentComponent != null) {
  36. root.legacy_renderSubtreeIntoContainer(parentComponent,children,callback);
  37. } else {
  38. root.render(children, callback);
  39. }
  40. }
  41. return getPublicRootInstance(root._internalRoot);
  42. }
  43. function legacyCreateRootFromDOMContainer(container: DOMContainer,forceHydrate: boolean) {
  44. //...
  45. const isConcurrent = false;
  46. return new ReactRoot(container, isConcurrent, shouldHydrate);
  47. }

在legacyCreateRootFromDOMContainer中会创建ReactRoot实例,在创建ReactRoot实例时会创建 FiberRoot(ReactRoot中createContainer创建),FiberRoot用于记录着这棵树的信息。请看在官网查看ReactRoot的具体代码

ReactRoot的实例

image.png
其中current是 createHostRootFiber -> createFiber(HostRoot, null, null, mode); 此时的mode值为4。

ReactRoot.render

root.render 其实是ReactRoot.render,用于渲染整棵树,代码如下:

  1. ReactRoot.prototype.render = function (children, callback) {
  2. var root = this._internalRoot;
  3. var work = new ReactWork();
  4. callback = callback === undefined ? null : callback;
  5. if (callback !== null) {
  6. work.then(callback);
  7. }
  8. updateContainer(children, root, null, work._onCommit);
  9. return work;
  10. };

updateContainer 开始渲染ReactRoot。