文件目录

packages/react/src/ReactElement

ReactElement

指定当前元素是 ReactElement, 但该元素是由 createElement 创建的, 来看一下ReactElement 源码

const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    $$typeof: REACT_ELEMENT_TYPE,   // 指Element元素

    // 下面几个都是我们 元素的属性,
    // eg. <div key="1" ref="string" value="123"></div>
    type: type,                
    key: key,                    
    ref: ref,                      
    props: props, 

    // 记录负责创建此元素的组件。
    _owner: owner,  // 其实是一个FiberNode
  };

  return element;
};

createElement

文档

根据type 创建一个ReactElement。同时处理ref, key, props, 还有children, 另外对defaultProps 赋值

我们看一下babel 的转化吧!

<div key="1" ref="string" value="123">
    <p>children1</p>
    <p>children2</p>
</div>

会转换成

React.createElement(
    "div", 
    {
        ref: "string",
        value: "123",
        key: "1"
    },
    React.createElement(
        "p", 
        null,
        "children1",
    )
    React.createElement(
        "p", 
        null,
        "children12",
    )
)

源码:

export function createElement(type, config, children) {
    // type => div
    // config => {ref: "string",value: "123",key: "1"}
    // children => <p>children1</p>, <p>children2</p>

    let propName;

    const props = {};

    let key = null;
    let ref = null;
    let self = null;
    let source = null;

    //  验证config, 把key 和 ref 从config 单独抽离出来放到props 中
    if (config != null) {
        // 验证 ref 和 key
        if (hasValidRef(config)) {
            ref = config.ref;
        }
        if (hasValidKey(config)) {
            key = '' + config.key;
        }

        // self 正确获取this, 检测this与 ReactElement.owner是否相等,不相等就发出警告
        // source 一个注释对象(由编译器或其他方式添加),指示文件名,行号和/或其他信息。
        self = config.__self === undefined ? null : config.__self;
        source = config.__source === undefined ? null : config.__source;

        // 遍历配置,把除了key, ref, _self, _source这些以外的数据放到props
        for (propName in config) {
            if (
                hasOwnProperty.call(config, propName) &&
                !RESERVED_PROPS.hasOwnProperty(propName)
            ) {
                props[propName] = config[propName];
            }
        }
    }

    // 处理children, arguments 后面的参数都是children
    // 如果children 数大于1个,那么放入到数组中
    const childrenLength = arguments.length - 2;
    if (childrenLength === 1) {
        props.children = children;
    } else if (childrenLength > 1) {
        const childArray = Array(childrenLength);
        for (let i = 0; i < childrenLength; i++) {
            childArray[i] = arguments[i + 2];
        }
        props.children = childArray;
    }

    // 判断是否有给组件设置 defaultProps,有的话判断是否有给 props 赋值,
    // 只有当值为 undefined 时,才会设置默认值
    if (type && type.defaultProps) {
        const defaultProps = type.defaultProps;
            for (propName in defaultProps) {
            if (props[propName] === undefined) {
                props[propName] = defaultProps[propName];
            }
        }
    }

    return ReactElement(
        type,
        key,
        ref,
        self,
        source,
        ReactCurrentOwner.current,
        props,
    );
}

cloneElement

文档

cloneElement 克隆元素, 大致跟createElement 的处理方式一样 。