react02

JSX渲染机制

  1. 基于BABEL中的语法解析模块(BABEL-PRESET-REACT)把JSX语法编译为 React.createElement(…) 结构

    1
    2
    3
    4
    5
    React.createElement(
    'h1',
    {id: 'titleBox',className: 'title',style: styleObj},
    '\u73E0\u5CF0\u57F9\u8BAD' //转义字符
    );
    1. 执行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
      }
    1. ReactDOM.render(JSX语法最后生成的对象,容器),基于RENDER方法把生成的对象动态创建为DOM圆度,插入到指定的容器中

    React.createElement模拟

  2. 创建一个对象(默认有四个属性:TYPE/PROPS/REF/KEY),最后要把这个对象返回
  3. 根据传递的值修改这个对象
    • 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function render(objJSX, container, callBack) {
let {type, props} = objJSX,
{children} = props;
let newElement = document.createElement(type);
for (let attr in props) {
if (!props.hasOwnProperty(attr)) break;
let value = props[attr];
if (value == undefined) continue;//=>NULL OR UNDEFINED

switch (attr.toUpperCase()) {
case 'CLASSNAME':
newElement.setAttribute('class', value);
break;
case 'STYLE':
for (let styleAttr in value) {
if (value.hasOwnProperty(styleAttr)) {
newElement['style'][styleAttr] = value[styleAttr];
}
}
break;
case 'CHILDREN':
/*
* 可能是一个值:可能是字符串也可能是一个JSX对象
* 可能是一个数组:数组中的每一项可能是字符串也可能是JSX对象
*/
//->首先把一个值也变为数组,这样后期统一操作数组即可
!(value instanceof Array) ? value = [value] : null;
value.forEach((item, index) => {
//->验证ITEM是什么类型的:如果是字符串就是创建文本节点,如果是对象,我们需要再次执行RENDER方法,把创建的元素放到最开始创建的大盒子中
if (typeof item === 'string') {
let text = document.createTextNode(item);
newElement.appendChild(text);
} else {
render(item, newElement);
}
});
break;
default:
newElement.setAttribute(attr, value);
}
}
container.appendChild(newElement);
callBack && callBack();
}


render(objJSX, root, () => {
console.log('ok');
});

REACT组件

不管是VUE还是REACT框架,设计之初都是期望我们按照“组件/模块管理”的方式来构建程序的,也就是把一个程序划分为一个个的组件来单独处理

优势

  1. 有助于多人协作开发
  2. 我们开发的组件可以被复用

    REACT中创建组件有两种方式:

  • 函数声明式组件
  • 基于继承COMPONENT类来创建组件
  • SRC -> COMPONENT :这个文件夹中存放的就是开发的组件
  1. 基于继承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元素,插入到指定的容器中即可

===================================

总结:创建组件有两种方式 “函数式”、“创建类式”

函数式

  1. 操作非常简单
  2. 能实现的功能也很简单,只是简单的调取和返回JSX而已

创建类式

  1. 操作相对复杂一些,但是也可以实现更为复杂的业务功能
  2. 能够使用生命周期函数操作业务
  3. 函数式可以理解为静态组件(组件中的内容调取的时候就已经固定了,很难在修改),而类这种方式,可以基于组件内部的状态来动态更新渲染的内容
-------------本文结束感谢您的阅读-------------