🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
react入口文件: ``` packages/react/src/React.js ``` **ReactElement文件** `packages/react/src/ReactElement.js` ``` export function createElement(type, config, children) { // 1:type是结点类型,如果是原生的节点,那么就是string, 如果是function component和class component就是组件,也可以是react原生的组件比如: Fragment: REACT_FRAGMENT_TYPE, StrictMode: REACT_STRICT_MODE_TYPE, Suspense: REACT_SUSPENSE_TYPE, 2:config就是写在js标签上的所有的attr ,变成key:value 3:子标签 let propName; // Reserved names are extracted const props = {}; let key = null; let ref = null; let self = null; let source = null; if (config != null) { if (hasValidRef(config)) { ref = config.ref; } if (hasValidKey(config)) { key = '' + config.key; } self = config.__self === undefined ? null : config.__self; source = config.__source === undefined ? null : config.__source; // Remaining properties are added to a new props object for (propName in config) { if ( hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName) ) { props[propName] = config[propName]; } } } 如果不是内嵌的props就放在新建的props中 // Children can be more than one argument, and those are transferred onto // the newly allocated props object. const childrenLength = arguments.length - 2; //后续的参数都认为是children 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; } // Resolve default props //class Comp extends React.Component //Comp.defaultProps = {value:1} 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, ); } ``` 内嵌的 ``` const RESERVED_PROPS = { key: true, ref: true, __self: true, __source: true, }; ``` ``` const ReactElement = function(type, key, ref, self, source, owner, props) { const element = { // This tag allows us to uniquely identify this as a React Element $$typeof: REACT_ELEMENT_TYPE, // $$typeof:用来标示element是什么类型都的, // 在写jsx代码的时候都是通过ReactElement创建的, // 所有$$typeof:都是REACT_ELEMENT_TYPE, // Built-in properties that belong on the element type: type, key: key, ref: ref, props: props, // Record the component responsible for creating this element. _owner: owner, }; return element; }; ``` `ReactElement`通过`createElement`创建,调用该方法需要传入三个参数: * type * config * children `type`指代这个`ReactElement`的类型 * 字符串比如`div`,`p`代表原生DOM,称为`HostComponent` * Class类型是我们继承自`Component`或者`PureComponent`的组件,称为`ClassComponent` * 方法就是`functional Component` * 原生提供的`Fragment`、`AsyncMode`等是Symbol,会被特殊处理 * TODO: 是否有其他的 从源码可以看出虽然创建的时候都是通过`config`传入的,但是`key`和`ref`不会跟其他`config`中的变量一起被处理,而是单独作为变量出现在`ReactElement`上。 在最后创建`ReactElement`我们看到了这么一个变量`$$typeof`,这是个啥呢,在这里可以看出来他是一个常量:`REACT_ELEMENT_TYPE`,但有一个特例:`ReactDOM.createPortal`的时候是`REACT_PORTAL_TYPE`,不过他不是通过`createElement`创建的,所以他应该也不属于`ReactElement` `ReactElement`只是一个用来承载信息的容器,他会告诉后续的操作这个节点的以下信息: 1. `type`类型,用于判断如何创建节点 2. `key`和`ref`这些特殊信息 3. `props`新的属性内容 4. `$$typeof`用于确定是否属于`ReactElement` 这些信息对于后期构建应用的树结构是非常重要的,**而React通过提供这种类型的数据,来脱离平台的限制**