React 首次渲染

76 阅读2分钟

导语

React 中的 key 真实的工作原理是怎么样的。

简易开发脚手架

快速开启一个全新的项目,选用 rollup 尝鲜。不使用 create-react-app ,是因为其内置了 React ,导致解析时无法使用我们自己的 React 版本。

  • 添加 @babel/preset-react ,帮助我们解析转换 jsx 语法
  • 注意 config 中 Babel 的添加顺序,保证先转换语法后再进行其他操作
  • 添加 prettier,自动格式化

Babel

React 中引入 Jsx 的语法来编写 html 和 js ,这种混合的写法 js 引擎并不认识,所以需要 Babel 来转译 Jsx。同理我们可以使用先进的 es6+ 的语法,依托 Babel 转译为低版本浏览器可以识别的 es5 语法。

[Jsx 转译](babeljs.io/repl#?brows…](babeljs.io/repl#?brows…)

ReactElement

React 帮助我们屏蔽了底层的各种 dom 操作,使得我们可以专心操作 UI 组件,核心是 virtual dom 的概念,用一个简单的对象来表示一个 dom 节点,这个对象具体的实现就是一个 reactElement , 我们在使用的过程中常用的dom 组件、函数式组件、类组件等,都会被创建成对应类型的 reactElement 。

React.createElement=function(type,config,children){
  ///
  return {
    $$typeof,
    type,
    props,
    key,
    ref,
  }
}

ReactDom.render

负责首次渲染,核心逻辑3条:

  1. 根据传入的 elementtype不同,分别生成不同的操作实例。
  2. 调用生成实例的 mountComponent 方法,生成真实的 dom
  3. 将真实的 dom 挂载到传入的 container 上面。

操作类,用来管理具体的 dom 节点的挂载、更新、卸载操作。通用的结构如下:

class ReactXXXComponent {
  constructor(element){
    this._currentElement = element;
    this._hostNode = null;
  }

  // 挂载
  mountComponent(){
    let dom = null;
    this._hostNode = null;
    return dom = null;
  }

  // 更新
  updateComponent(){}

  // 卸载
  unmountComponent(){
    this._currentElement = null;
    this._hostNode = null;
  }
}

首次挂载后,将生成的真实dom保存在 _hostNode 上。

React 实例关系图

核心是 React Element,React 获取到 React Element 后,生成不同的操作实例。

未命名绘图.png

实际应用中,主要应用的是 ReactCompositeComponent 组件。很少会直接用到一段纯 UI 的 ReactDomComponent,通常都会在 ReactDomComponent 的基础上添加自有的 state。

操作实例.png