# react解析: render的FiberRoot(三)

感谢 yck: 剖析 React 源码解析 (opens new window),本篇文章是在读完他的文章的基础上,将他的文章进行拆解和加工,加入我自己的一下理解和例子,便于大家理解。觉得yck (opens new window)写的真的很棒 。React 版本为 16.8.6,关于源码的阅读,可以移步到yck react源码解析 (opens new window)

本文永久有效链接: react解析 render的FiberRoot(三) (opens new window)

下面将会说到 ReactDOM.render 在ReactDOM中的调用流程,实际就是分析下面代码:

ReactDOM.render(<APP />, document.getElementById('app'))
1

实际代码:

ReactDOM.render(React.createElement(APP, null), document.getElementById('app'));
1

下面我们将从ReactDOM常量对象的render方法开始解析。

# render 函数

yck: ReactDOM 源码 702行 render (opens new window)

ReactDOM.render实际调用的就是下面的代码

render(
    element: React$Element<any>,
    container: DOMContainer,
    callback: ?Function,
  ) {
    // 注意下 forceHydrate 参数,为 true 时是服务端渲染
    // 客户端调用 render 函数的话这个值永远为 false
    return legacyRenderSubtreeIntoContainer(
      null,
      element,
      container,
      false,
      callback,
    );
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

render函数中的参数element是 传入的组件,containerDOM节点容器,callback是回调函数。ReactDOM.render文档 (opens new window)

# legacyRenderSubtreeIntoContainer 函数

yck: ReactDOM 源码 554行 legacyRenderSubtreeIntoContainer (opens new window)

function legacyRenderSubtreeIntoContainer(
  parentComponent: ?React$Component<any, any>,
  children: ReactNodeList,
  container: DOMContainer,
  forceHydrate: boolean,
  callback: ?Function,
) {
    // 初始化时,container 肯定没有 _reactRootContainer属性
    let root: Root = (container._reactRootContainer: any);
    if (!root) {
        root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
            container,    // DOM容器节点
            forceHydrate, // 为false
        );
        // 暂时只说root不存在时,reactRoot的创建
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

container表示DOM元素节点容器, 在上面的代码中会创建一个ReactRoot,然后将它挂载在container容器上, container._reactRootContainer就是挂载的ReactRoot实例对象;root也是一个ReactRoot实例对象。

// 查看_reactRootContainer
document.getElementById('app')._reactRootContainer
1
2

# 创建FiberRoot核心函数

yck: ReactDOM 源码 504行 legacyCreateRootFromDOMContainer (opens new window)

function legacyCreateRootFromDOMContainer(
  container: DOMContainer,
  forceHydrate: boolean,
): Root {
  const isConcurrent = false;
  // 调用ReactRoot函数 创建ReactRoot, shouldHydrate是SSR相关,不用管
  return new ReactRoot(container, isConcurrent, shouldHydrate);
}
1
2
3
4
5
6
7
8

创建ReactRoot实例对象,同时返回

yck: ReactDOM 源码 368行 ReactRoot (opens new window)

function ReactRoot(
  container: DOMContainer,
  isConcurrent: boolean,
  hydrate: boolean,
) {
  // 这个 root 指的是 FiberRoot
  const root = createContainer(container, isConcurrent, hydrate);
  this._internalRoot = root;
}
1
2
3
4
5
6
7
8
9

调用createContainer 创建FiberRoot,下面我们将会说到FiberRoot 对象

# FiberRoot

yck: ReactDOM 源码 368行 createContainer (opens new window)

export function createContainer(
  containerInfo: Container,
  isConcurrent: boolean,
  hydrate: boolean,
): OpaqueRoot {
  return createFiberRoot(containerInfo, isConcurrent, hydrate);
}
1
2
3
4
5
6
7

yck: ReactDOM 源码 368行 createFiberRoot (opens new window)

function createFiberRoot(
  containerInfo: any,
  isConcurrent: boolean,
  hydrate: boolean,
): FiberRoot {
  const root: FiberRoot = (new FiberRootNode(containerInfo, hydrate): any);
  const uninitializedFiber = createHostRootFiber(isConcurrent);
  root.current = uninitializedFiber;
  uninitializedFiber.stateNode = root;

  return root;
}
1
2
3
4
5
6
7
8
9
10
11
12

createFiberRoot函数中,首先创建了一个root: FiberRoot,然后又创建了一个uninitializedFiber: RootFiber,它们两者还是相互引用。这里即是创建FiberRoot的主要函数

// 查看 FiberRoot 对象
document.getElementById('app')._reactRootContainer._internalRoot
1
2

我们下面顺便说一下FiberRoot 和 RootFiber的关系,同时拿出几个必须要要了解的属性解释一下。

ReactDom.render(
  ()=> (
    <div>
      <div></div>
      <div></div>
    </div>
  ), 
  document.querySelector('#root')
)
1
2
3
4
5
6
7
8
9

img

以上图片中只有FiberRoot的部分属性,想了解更多,可以查看FiberRoot的数据结构 (opens new window)哦!!

更多内容:

react解析: React.createElement(一) (opens new window)

react解析: React.Children(二) (opens new window)

react解析: render的FiberRoot(三) (opens new window)

参考:

yck: 剖剖析 React 源码 (opens new window)

Jokcy 的 《React 源码解析》: react.jokcy.me/ (opens new window)

ps: 顺便推一下自己的个人公众号:Yopai,有兴趣的可以关注,每周不定期更新,分享可以增加世界的快乐

🥰Me

男性,武汉工作,会点Web,擅长Javascript.

技术或工作问题交流,可联系微信:1169170165.

🚀小程序&公众号
🚀运行
2024年2月19日星期一下午2点01分
博客已运行:--天--时--分--秒
上次更新: 7/18/2023, 6:00:41 PM

评 论: