create-react-app 1.jsx
import React, { Component } from './react';
import ReactDOM from 'react-dom';
class App extends Component {
render() {
return (
<div>
<p>1</p>
<button>+</button>
</div>
)
}
}
let element = <App />;
console.log(element);
ReactDOM.render(
element
, document.getElementById('root'));
/**
class App extends Component {
render() {
return React.createElement("div", null,
React.createElement("p", null, "1"),
React.createElement("button", null, "+"));
}
}
let element = React.createElement(App, null);
*/
src\react\index.js
import { createElement } from './ReactElement';
import { Component } from './ReactBaseClasses';
const React = {
createElement
}
export {
Component
}
export default React;
src\react\ReactElement.js
import ReactCurrentOwner from './ReactCurrentOwner';
import { REACT_ELEMENT_TYPE } from '../shared/ReactSymbols';
const RESERVED_PROPS = {
key: true,
ref: true,
__self: true,// __self 是为了以后正确获取 this
__source: true,
};
function hasValidRef(config) {
return config.ref !== undefined;
}
function hasValidKey(config) {
return config.key !== undefined;
}
export function createElement(type, config, children) {
let propName;
//保留的属性被移除掉了
const props = {};
let key = null;
let ref = null;
let self = null;//获取this指向
let source = null;//获取行等信息
// 判断是否传入配置
if (config != null) {
// 验证 ref 和 key
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
// __self 是为了以后正确获取 this
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// 遍历配置,把非保留属性拷贝到props上去
for (propName in config) {
if (!RESERVED_PROPS.hasOwnProperty(propName)) {
props[propName] = config[propName];
}
}
}
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,
);
}
//这是一个工厂函数,帮助我们创建React元素
const ReactElement = function (type, key, ref, self, source, owner, props) {
const element = {
//这个标志让我们可以唯一的标识这是一个React元素
$$typeof: REACT_ELEMENT_TYPE,
//此元素的内建属性
type: type,
key: key,
ref: ref,
props: props,
//记录一下创建此元素组件
_owner: owner,
};
element._self = self;
element._source = source;
return element;
};
src\react\ReactCurrentOwner.js
const ReactCurrentOwner = {
current: null
};
export default ReactCurrentOwner;
src\shared\ReactSymbols.js
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
export const REACT_ELEMENT_TYPE = hasSymbol
? Symbol.for('react.element')
: 0xeac7;
export const REACT_FORWARD_REF_TYPE = hasSymbol
? Symbol.for('react.forward_ref')
: 0xead0;
src\react\ReactBaseClasses.js
class Component {
constructor(props, context) {
this.props = props;//属性对象
this.context = context;//上下文对象
}
}
Component.prototype.isReactComponent = {
}
class PureComponent extends Component {
}
PureComponent.prototype.isPureReactComponent = {}
/* function ComponentDummy() { }
ComponentDummy.prototype = Component.prototype;
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
this.refs = emptyObject;
this.updater = updater;
}
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true; */
export { Component, PureComponent };
React.Children.map(children, function[(thisArg)])
src\index.js
import React, { Component } from './react';
import ReactDOM from 'react-dom';
class Child extends Component {
render() {
console.log(this.props.children);
const mappedChildren = React.Children.map(
this.props.children,
(item, index) => (
<div key={index}>{item}</div>
)
);
console.log(mappedChildren);
return (
<div>
{mappedChildren}
</div>
)
}
}
class App extends Component {
render() {
return (
<Child><span >A</span></Child>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
src\react\ReactChildren.js
import { REACT_ELEMENT_TYPE } from '../shared/ReactSymbols';
function mapChildren(children, mapFunction, context) {
const result = [];
mapIntoWithKeyPrefixInternal(children, result, mapFunction, context);
return result;
}
function mapIntoWithKeyPrefixInternal(children, result, mapFunction, context) {
const traverseContext = { result, mapFunction, context };
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
}
function traverseAllChildren(children, mapSingleChildIntoContext, traverseContext) {
const type = typeof children;
if (type === 'string' || type === 'number' || (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)) {
mapSingleChildIntoContext(
traverseContext,
children
);
}
}
function mapSingleChildIntoContext(traverseContext, child) {
const { result, mapFunction, context } = traverseContext;
let mappedChild = mapFunction.call(context, child);
result.push(mappedChild);
}
export {
mapChildren as map,
};
src\index.js
import React, { Component } from './react';
import ReactDOM from 'react-dom';
class Child extends Component {
render() {
console.log(this.props.children);
const mappedChildren = React.Children.map(
this.props.children,
(item, index) => (
<div key={index}>{item}</div>
)
);
console.log(mappedChildren);
return (
<div>
{mappedChildren}
</div>
)
}
}
class App extends Component {
render() {
return (
+ <Child><span >A</span><span >B</span></Child>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
src\react\ReactChildren.js
import { REACT_ELEMENT_TYPE } from '../shared/ReactSymbols';
function mapChildren(children, mapFunction, context) {
const result = [];
mapIntoWithKeyPrefixInternal(children, result, mapFunction, context);
return result;
}
function mapIntoWithKeyPrefixInternal(children, result, mapFunction, context) {
const traverseContext = { result, mapFunction, context };
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
}
function traverseAllChildren(children, mapSingleChildIntoContext, traverseContext) {
const type = typeof children;
if (type === 'string' || type === 'number' || (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)) {
mapSingleChildIntoContext(
traverseContext,
children
);
}
+ if (Array.isArray(children)) {
+ for (let i = 0; i < children.length; i++) {
+ traverseAllChildren(children[i], mapSingleChildIntoContext, traverseContext);
+ }
+ }
}
function mapSingleChildIntoContext(traverseContext, child) {
const { result, mapFunction, context } = traverseContext;
let mappedChild = mapFunction.call(context, child);
result.push(mappedChild);
}
export {
mapChildren as map,
};
src\index.js
import React, { Component } from './react';
import ReactDOM from 'react-dom';
class Child extends Component {
render() {
+ console.log(this.props.children);
+ const mappedChildren = React.Children.map(
+ this.props.children,
+ (item) => (
+ [item, [item, [item, item]]]
+ )
+ );
+ console.log(mappedChildren);
return (
<div>
{mappedChildren}
</div>
)
}
}
class App extends Component {
render() {
return (
<Child>
<span >A</span>
<span >B</span>
</Child>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
src\react\ReactChildren.js
import { REACT_ELEMENT_TYPE } from '../shared/ReactSymbols';
function mapChildren(children, mapFunction, context) {
const result = [];
mapIntoWithKeyPrefixInternal(children, result, mapFunction, context);
return result;
}
function mapIntoWithKeyPrefixInternal(children, result, mapFunction, context) {
const traverseContext = { result, mapFunction, context };
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
}
function traverseAllChildren(children, mapSingleChildIntoContext, traverseContext) {
const type = typeof children;
if (type === 'string' || type === 'number' || (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)) {
mapSingleChildIntoContext(
traverseContext,
children
);
}
if (Array.isArray(children)) {
for (let i = 0; i < children.length; i++) {
traverseAllChildren(children[i], mapSingleChildIntoContext, traverseContext);
}
}
}
function mapSingleChildIntoContext(traverseContext, child) {
const { result, mapFunction, context } = traverseContext;
let mappedChild = mapFunction.call(context, child);
+ if (Array.isArray(mappedChild)) {
+ mapIntoWithKeyPrefixInternal(mappedChild, result, c => c);
+ } else if (mappedChild != null) {
+ result.push(mappedChild);
+ }
}
export {
mapChildren as map,
};
src\index.js
import React, { Component } from './react';
import ReactDOM from 'react-dom';
class Child extends Component {
render() {
console.log(this.props.children);
const mappedChildren = React.Children.map(
this.props.children,
(item) => (
+ [item, [item, [item, item]]]
)
);
console.log(mappedChildren);
return (
<div>
{mappedChildren}
</div>
)
}
}
class App extends Component {
render() {
return (
<Child>
+ {[<span >A</span>, <span >B</span>]}
+ {[<span >C</span>, <span >D</span>]}
</Child>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
src\react\ReactChildren.js
import { REACT_ELEMENT_TYPE } from '../shared/ReactSymbols';
+const SEPARATOR = '.';
+const SUBSEPARATOR = ':';
function mapChildren(children, mapFunction, context) {
const result = [];
+ mapIntoWithKeyPrefixInternal(children, result, null, mapFunction, context);
return result;
}
function mapIntoWithKeyPrefixInternal(children, result, prefix, mapFunction, context) {
+ if (prefix != null) {
+ prefix = prefix + '/';
+ }
+ const traverseContext = { result, prefix, mapFunction, context };
+ traverseAllChildren(children, '', mapSingleChildIntoContext, traverseContext);
}
+function traverseAllChildren(children, nameSoFar, mapSingleChildIntoContext, traverseContext) {
const type = typeof children;
if (type === 'string' || type === 'number' || (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)) {
+ mapSingleChildIntoContext(
+ traverseContext,
+ children,
+ nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar
+ );
}
if (Array.isArray(children)) {
+ let child;
+ let nextName;
+ const nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;
for (let i = 0; i < children.length; i++) {
+ child = children[i];
+ nextName = nextNamePrefix + getComponentKey(child, i);
+ traverseAllChildren(child, nextName, mapSingleChildIntoContext, traverseContext);
}
}
}
+function mapSingleChildIntoContext(traverseContext, child, childKey) {
+ const { result, prefix, mapFunction, context } = traverseContext;
let mappedChild = mapFunction.call(context, child);
if (Array.isArray(mappedChild)) {
+ mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c);
} else if (mappedChild != null) {
+ result.push({ ...mappedChild, key: prefix + childKey });
}
}
+function getComponentKey(component, index) {
+ return component.key || index.toString(36);
+}
export {
mapChildren as map
};