react中的jsx丶实现原生dom的渲染丶函数组件丶类组件的首次渲染实现

Posted lin-fighting

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react中的jsx丶实现原生dom的渲染丶函数组件丶类组件的首次渲染实现相关的知识,希望对你有一定的参考价值。

jsx

  • jsx在babel的帮助下可以转换为react.createElement方法的调用,如

    PURE是treeshaking的时候用的,标志这是个纯函数。
  • 新老版本的区别
    在17之前,我们需要显示引入React,然后Babel转化为React.CreateElement方法,而新的版本中不需要显示引入React,react会自动转化为(Object.s_jsx)方法。
  • JSX只是react提供的一个语法糖,react元素是构建react应用的最小 单位。如,let elemtn = < div>13</ div>,这个element就是一个react元素。打印一下看看
{
    "type": "div", 元素的类型
    "key": null, diff算法用到,用来区分同个父亲不同儿子
    "ref": null, 获取真实dom ref的时候会用到
    "props": { 属性
        "children": "123123" 
    },
    "_owner": null,
    "_store": {}
}

这就是一个react元素,所谓的虚拟dom,也就是一个普通的js对象。

  • 所谓的渲染就是按照react元素描述的结构,创建真实的dom元素,并插入到root容器内。会由ReactDom这个对象来确保浏览器的真实dom与虚拟dom是一致的。
  • 就好比设计师设计出了图纸,工人根据其图纸在指定地点建造房子,房子的造型的图纸是一致的。

JSX表达式

  • 表达式就是变量,常量,操作符混合在一起的组合,是可以计算的,而且肯定会有一个返回值。
{
    "type": "div",
    "key": null,
    "ref": null,
    "props": { //属性
        "style": {
            "color": "red"
        },
        "children": "123world"
    },
    "_owner": null,
    "_store": {}
}

返回一个react元素。

  • JSX可以作为函数的参数和返回值。


  • 效果是一样的。

元素的更新

  • React元素本身是不可变的,即react元素(这个对象是不可扩展的,react17前可以扩展,就好比freeze冻结住了,freeze不可扩展,不可删除,不可修改,浅冻结,seal,不可扩展,可以删除可以修改)的属性,是只读的,不可改。react内部使用了freeze,比如:
    可以通过创建新的元素来重新render。ReactDom.render更新不是全量更新,只会更新该更新的部分。

实现原生dom的渲染(react15)

实现createElement以及ReactDom.render
流程

先定义一个Jsx


用babel转换就是

createElement的实现

我们先实现createElement方法

createElement返回一个虚拟dom对象,需要做的处理是children的处理,有多个的话就要数组,一个的话就直接赋值。


效果:第一个是我们自己写的,第二个是React.createElement转化的。
因为后续会实现domdiff,所以必须对文本节点做一些特殊处理,也转换城虚拟dom对象。
定义类型

处理文本节点为虚拟do’m


对每个children进行处理

文本节点已经被处理为虚拟dom了。

render的实现

1 创建真实dom


通过createDom创建真实的dom

Props处理

先处理第一次渲染的Props。第一次主要就是处理style,事件。

props处理后就处理children


判断是多个子节点还是一个文本节点,文本节点直接赋值,多个节点就需要reconclierChildren方法,最后返回出去,因为这是createDom方法。需要返回一个dom

reconclier方法主要是递归拿到children,然后再去render递归遍历这也是react15的缺点,递归遍历无法中断。

函数组件 react15的函数组件是无状态的,所以我们先实现无状态的函数组件,

组件类似于js的函数,接受任意入参props,返回用于描述页面内容的react元素。


可以看到type值已经变成了函数。
也就是
把函数组件当作createElement的第一个值传入。效果是一样的。

实现渲染函数组件


因为我们是自己写的createElement,所以这里也换成自己写的。
首先,在createDom中需要判断函数组件。

调用mountFunctionComponent方法并返回,因为CreateDom需要返回一个dom。

这里直接执行该函数,将props传进去,然后拿到虚拟dom对象,再去调用createDom并返回。
效果
正常渲染。

类组件的首次渲染实现

组件分为内置原生组件和自定义组件,内置组件如p h1 div这些。自定义组件就是类组件,函数组件这些。怎么区分函数组件类组件呢?


在类组件的原型上有一个isReactComponent属性,而函数组件并没有。

实现React.Component

需要一个原型上的isReactComponent属性。


然后

只要在createDom里面判断该vdom是类组件。
new一个实例出来再调用render方法即可拿到react元素。再创建dom返回即可。

可以正常渲染。

总结:

从jsx到原生dom,到函数组件,再到类组件,
基本流程图就是这样,函数组件跟类组件都是返回一个react元素。类组件则是实例的render返回react元素,他们根据原型上的isReactComponent来判断是否是类组件。

以上是关于react中的jsx丶实现原生dom的渲染丶函数组件丶类组件的首次渲染实现的主要内容,如果未能解决你的问题,请参考以下文章

Linux中的用户丶组管理

preact 源码学习:JSX解析与DOM渲染

ReactReact全家桶React 概述+虚拟DOM的创建与渲染+JSX

ReactReact全家桶React 概述+虚拟DOM的创建与渲染+JSX

关于DOM 事件流的三个阶段

从 0 到 1 实现 React 系列 —— 组件和 state|props