JSX渲染机制
基于BABEL中的语法解析模块(BABEL-PRESET-REACT)把JSX语法编译为 React.createElement(…) 结构
1
2
3
4
5React.createElement(
'h1',
{id: 'titleBox',className: 'title',style: styleObj},
'\u73E0\u5CF0\u57F9\u8BAD' //转义字符
);- 执行React.createElement(type, props, children),创建一个对象(虚拟DOM)
1
2
3
4
5
6
7
8
9
10
11
12
13{
type:'h1'
props:{
id:'titleBox',
className:'title',
style:...,
children:'珠峰培训' //存放的是素中的内容
}
ref:null,
key:null,
...
__proto__:Object.prototype
}
- ReactDOM.render(JSX语法最后生成的对象,容器),基于RENDER方法把生成的对象动态创建为DOM圆度,插入到指定的容器中
React.createElement模拟
- 执行React.createElement(type, props, children),创建一个对象(虚拟DOM)
- 创建一个对象(默认有四个属性:TYPE/PROPS/REF/KEY),最后要把这个对象返回
- 根据传递的值修改这个对象
- TYPE =>传递的TYPE
- PROPS 需要做一些处理:大部分传递PROPS中的属性都赋值给对象的PROPS,有一些比较特殊
- 如果是REF或者KEY,我们需要把传递的PROPS中的这两个属性值,给创建对象的两个属性,而传递的PROPS中把这两个值删除掉
- 把传递的CHILDREN作为新创建对象的PROPS中的一个属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24/*
* CREATE-ELEMENT:创建JSX对象
* 参数:至少两个 TYPE/PROPS,CHILDREN这个部分可能没有可能有多个
*/
function createElement(type, props, ...childrens) {
let ref, key;
if ('ref' in props) {
ref = props['ref'];
props['ref'] = undefined;
}
if ('key' in props) {
key = props['key'];
props['key'] = undefined;
}
return {
type,
props: {
...props,
children: childrens.length <= 1 ? (childrens[0] || '') : childrens
},
ref,
key
};
}
RENDER:把创建的对象生成对应的DOM元素,最后插入到页面中
1 | function render(objJSX, container, callBack) { |
REACT组件
不管是VUE还是REACT框架,设计之初都是期望我们按照“组件/模块管理”的方式来构建程序的,也就是把一个程序划分为一个个的组件来单独处理
优势
- 有助于多人协作开发
我们开发的组件可以被复用
REACT中创建组件有两种方式:
- 函数声明式组件
- 基于继承COMPONENT类来创建组件
- SRC -> COMPONENT :这个文件夹中存放的就是开发的组件
基于继承COMPONENT类来创建组件
基于CREATE-ELEMENT把JSX转换为一个对象,当RENDER渲染这个对象的时候,遇到TYPE是一个函数或者类,不是直接创建元素,而是先把方法执行:- 如果是函数式声明的组件,就把它当做普通方法执行(方法中的THIS是UNDEFINED),把函数返回的JSX元素(也是解析后的对象)进行渲染
- 如果是类声明式的组件,会把当前类NEW它执行,创建类的一个实例(当前本次调取的组件就是它的实例),执行CONSTRUCTOR之后,会执行THIS.RENDER(),把RENDER中返回的JSX拿过来渲染,所以“类声明式组件,必须有一个RENDER的方法,方法中需要返回一个JSX元素”
但是不管是哪一种方式,最后都会把解析的出来的PROPS属性对象作为实参传递给对应的函数或者类
知识点:
CREATE-ELEMENT在处理的时候,遇到一个组件,返回的对象中:TYPE就不在是字符串标签名了,而是一个函数(类),但是属性还是存在PROPS中
1
2
3
4
5
6
7
8 {
type:Dialog,
props:{
lx:1,
con:'xxx',
children:一个值或者一个数组
}
}
RENDER渲染的时候,我们需要做处理,首先判断TYPE的类型,如果是字符串,就创建一个元素标签,如果函数或者类,就把函数执行,把PROPS中的每一项(包含CHILDREN)传递给函数
在执行函数的时候,把函数中RERURN的JSX转换为新的对象(通过CREATE-ELEMENT),把这个对象返回;紧接着RENDER按照以往的渲染方式,创建DOM元素,插入到指定的容器中即可
===================================
总结:创建组件有两种方式 “函数式”、“创建类式”
函数式
- 操作非常简单
- 能实现的功能也很简单,只是简单的调取和返回JSX而已
创建类式
- 操作相对复杂一些,但是也可以实现更为复杂的业务功能
- 能够使用生命周期函数操作业务
- 函数式可以理解为静态组件(组件中的内容调取的时候就已经固定了,很难在修改),而类这种方式,可以基于组件内部的状态来动态更新渲染的内容