React essence note - 1 - JSX

JSX 的本质是什么, 它和 JS 之间到底是什么关系?

  • JSX 的本质 JavaScript 的语法扩展
  • JSXJavaScript 的一种语法扩展,它和模板语言很接近,但是它充分具备 JavaScript 的能力.

JSX 语法是如何在 JavaScript 中生效的

  • JSX 会被编译为 React.createElement(), React.createElement() 将返回一个叫做 React ElementJS对象
  • 上面提到的 编译Babel 完成

什么是Babel?

  • Babel是一个工具链(语法转换器), 主要用于将 ES2015+的代码转换为向后兼容的 JavaScript语法, 以便能够运行在当前和旧版本的浏览器或者其他环境中
  • Babel也具备将JSX语法转换为JavaScript代码的能力.
<!-- JSX -->
<div className="app">
  <div class="title"> I am Title </div>
  <div class="content"> I am content </div>
</div>
  • 转换为
// React.createElement
"use strict";

/*#__PURE__*/
React.createElement("div", {
  className: "app"
}, /*#__PURE__*/React.createElement("div", {
  class: "title"
}, " I am Title "), /*#__PURE__*/React.createElement("div", {
  class: "content"
}, " I am content "));
  • 所有的JSX标签都呗转化成为了React.creatElement调用. 我们写的JSX其实写的就是React.createElement,虽然看起来像HTML,但也只是“看起来像”而已.
  • JSX的本质: React.createElement 这个 JavaScript 调用的语法糖.(写一行JSX,就会调用React.createElement)

既然 JSX 等价于一次 React.createElement调用,什么官方不直接推荐我们用 React.createElement来创建元素呢?

  • 原因很简单,JSX 代码层次分明,嵌套关系清晰
  • React.createElement 代码则给人一种非常混乱的代码结构
  • JSX 语法糖允许前端开发者使用我们最为熟悉的类 HTML 标签语法来创建虚拟 DOM,在降低学习成本的同时,也提升了研发效率与研发体验。

为什么要用 JSX? 不用会有什么后果?

JSX 背后的功能模块是什么, 这个功能模块都做了哪些事情?

React.createElement 工作流程

  • 1: 入口 函数调用 React.createElement
  • 2: 二次处理 key, ref, self, source 四个属性值
  • 3: 遍历 config, 筛选出可以作为 props 的属性
  • 4: 提取子元素, 推入 childArray (props.children)数组
  • 5: 格式化 defaultProps
  • 6: 结合以上数据作为入参, 发出 React.createElement 调用

createElement 中并没有十分复杂的涉及算法或者真实 DOM 的逻辑,几乎每个步骤都在格式化数据

createElement 就像是 开发者ReactElement 调用之间的一个 转换器, 一个数据处理层

createElement: 开发者处接受相对简单的参数, 然后将这些参数按照 ReactElement的预期作一层格式化, 最终通过调用ReactElement实现元素的创建

createElement只是个 参数中介

ReactElement

  • createElement执行到最后会return一个针对ReactElement的调用
return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props)
  • ReactElement只做了一件事,创建,说得更精确一点, 组装
  • ReactElement 把传入的参数按照一定的规范, 组装进了 element对象里, 并把它返回给 React.createElement
const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // REACT_ELEMENT_TYPE是一个常量,用来标识该对象是一个ReactElement
    $$typeof: REACT_ELEMENT_TYPE,
    // 内置属性赋值
    type: type,
    key: key,
    ref: ref,
    props: props,
    // 记录创造该元素的组件
    _owner: owner,
  };
  // 
  if (__DEV__) {
    // 这里是一些针对 __DEV__ 环境下的处理,对于大家理解主要逻辑意义不大,此处我直接省略掉,以免混淆视听
  }
  return element; // 🚀 返回给 React.createElement
}
  • 最终 React.createElement 又把它交回到了开发者手中。整个过程如下图所示

  • 这个 ReactElement对象实例 本质上是以 JavaScript对象存在的对DOM的描述,也就是 虚拟DOM
  • 虚拟DOM真实DOMGapReactDOM.render()来填补

ReactDOM.render

ReactDOM.render(
    // 需要渲染的元素(ReactElement)
    element,
    // 元素挂载的模板容器(一个真实DOM)
    container,
    // 回调函数,可选参数,用来处理渲染结束后的逻辑
    [callback]
)
  • 第二个参数就是一个真实的 DOM 节点,这个真实的 DOM 节点充当“容器”的角色
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
posted @ 2020-10-22 21:49  荣光无限  阅读(104)  评论(0)    收藏  举报