我要拿捏 react 系列四: 了解JSX

163 阅读2分钟

可能有人问,为啥会突然讲这么基础的内容? 原因是这样的,最近工作实在太忙,没有时间看更难理解的内容,所以我想回到开始的章节,整理一下基础内容,谁说基础内容就没有含金量?看完后,我还是有收获的

JSX 是什么?

回答这个问题前,我们先来看下面这个问题: 在老版本的 React 中,为什么写 JSX 的文件要默认引入 React?

比如:

import React from   react
function Index(){return <div> hello,React </div>}

因为 JSX 在被 Babel 编译后,JSX 标签结构会变成 React.createElement 形式,所以需要引入React,防止找不到 React 引起报错。

了解React.createElement

前面讲到JSX语法里 闭合标签元素会被 React.createElement 处理, 看一下这个 API 的用法。

React.createElement(
    type,
    [props],
    [...children])

createElement 参数:

  • 第一个参数 type:如果是组件类型,会传入组件对应的类或函数; 如果是 DOM 元素类型,则传入 div 或者 span 之类的字符串。

  • 第二个参数 props:一个对象在 DOM 类型中为标签属性,在组件类型中为 props。

  • 其他参数 Children:依次为该元素的子元素,根据顺序排列。

  • 返回结果: React Element对象。

举个例子:

<div>
    <TextComponent /> 
    <div>hello,world</div> 
    let us learn React!
</div>

上面的代码会被 Babel 先编译成:

React.createElement(
    "div", null, 
    React.createElement(TextComponent, null), 
    React.createElement("div", null, "hello,world"), 
    "let us learn React!"
)

ReactElement 对象

由上述内容可知,ReactElement 对象是通过 React.createElement 创建出来的特殊对象。 它大致长这个样子

const element = {
    $$typeof: REACT_ELEMENT_TYPE, // Element 元素类型
    type: type,  // type 属性,证明是元素还是组件
    key: key, // key属性
    ref: ref, // ref属性
    props: props, // props属性
    ...
};

createElement 原理揭秘

export function createElement(type, config, children) {
    /* 初始化参数*/
    const props = {};
    let key = null,propName, ref = null, self = null, source = null;
    if (config != null) { /* 处理ref */ 
        if (hasValidRef(config)) {
            ref = config.ref; 
        }
        if (hasValidKey(config)) { /* 处理key */
            key =   ''  + config.key;
        }
        for (propName in config) { /*处理props */
            if (
                hasOwnProperty.call(config, propName) && 
                ! RESERVED_PROPS.hasOwnProperty(propName))       
            {props[propName]= config[propName];} 
        }
    }
/* 处理Children逻辑*/
const childrenLength = arguments.length - 2;
    if (childrenLength === 1) { // 只有一个 Children 的情况
        props.children = children;
    } else if (childrenLength > 1) { 
        // 存在多个 Children 的情况
        const childArray = Array(childrenLength);
        for (let i = 0; i < childrenLength; i++) {
            childArray[i]= arguments[i + 2]; 
        }
        props.children = childArray;
}
/* 省略处理 defaultProps */
return ReactElement(type,key,ref,self,source,
    ReactCurrentOwner.current,props,);
}

createElement 做的事情大致可以分为:

  1. 初始化参数,比如 props、key、ref 等。
  2. 单独处理 key 和 ref 属性,处理 props 里面的其他属性。
  3. 形成 Children 结构的数组。
  4. 通过 ReactElement 创建 Element 对象并返回。
const ReactElement = function(type, key, ref, self, source, 
    owner, props) {
    const element = {
        $$typeof: REACT_ELEMENT_TYPE, 
        type: type,
        key: key,
        ref: ref,
        props: props,
        _owner: owner,
    };
    /* 创建element对象*/ 
    return element;
};

ReactElement 作为一个纯函数,做的事情很简单,就是根据传进来的参数,创建并返回一个 Element对象。

好了,相信看完这些,我们对JSX和 createElement 有了一些原理上的认知,这些应该都是后面学习fiber结构的基础,所以 温故知新都必不可少呢,下期见