先讲一点react的基础部分:
1. react中创建组件的写法: var a = <Component {...props} />,实质上是React调用createElement方法,生成一个虚拟的DOM元素。等同于如下:var a = React.createElement(Component, props);
2. 创建类的写法: class Component{ },其本质是一个方法, 在babel中转化如下: 1 2 3 4 5 6 7 8 9 function _classCallCheck (instance, Constructor ) { if (!(instance instanceof Constructor)) { throw new TypeError ("Cannot call a class as a function" ); } } var Component = function Component ( ) { _classCallCheck(this , Component); };
1 2 3 var child = React.createElement('p' , { id : 'bbb' }, 'click me' );var app = React.createElement('button' , { id : 'aaa' , onClick : () => console .log(1111 ) }, child);ReactDOM.render(app, document .getElementById('root' ));
上述将生成一个包裹着p标签的button组件。ReactElement: 一个描述DOM节点或component实例的字面级对象。创建并返回一个新的react element元素及虚拟DOM对象。type可以是一个普通的标签名如div或span, 亦可以是react组件类型(class或是function)。
4. 提供一个改变组件名字的方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class ButtonForTest extends Component { render() { return ( <Button>1111 </Button> ) } } function addName(name, Component) { / / 接收一个名字,及一个组件 function WithName(props) { return <Component {...props} / >; } WithName.displayName = `${name} ` ; return WithName; } const newName = { key : addName('NewName' , ButtonForTest) };const NewComponent = <newName.key /> ; // -》 var c = React.createElement(newName.key, null);
上诉NewComponent所得为NewName组件下包含着ButtonForTest组件。
笔者一直感到奇怪,NewComponent获得的是一个带有display属性的function,并不是一个class,为什么也可以渲染出来呢。
其实上面已经说到了,类的本质就是一个方法。 <newName.key />转化为js的写法是 React.createElement(newName.key, null),createElement接收三个参数(type, config, children), type属性为字符串时,它代表是普通的节点,如div,span。type属性为一个函数或一个类时,它代表自定义的节点。因此上述方法即是获得一个addName方法返回的组件,其中对所要包裹的组件,(即第二个参数)外部包裹一层名为NewName 的组件。
5. 简单看一下react中createElement部分: 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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 ReactElement.createElement = function (type, config, children ) { var propName; var props = {}; var key = null ; var ref = null ; var self = null ; var 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; for (propName in config) { if ( hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName) ) { props[propName] = config[propName]; } } } var childrenLength = arguments .length - 2 ; if (childrenLength === 1 ) { props.children = children; } else if (childrenLength > 1 ) { var childArray = Array (childrenLength); for (var i = 0 ; i < childrenLength; i++) { childArray[i] = arguments [i + 2 ]; } if (__DEV__) { if (Object .freeze) { Object .freeze(childArray); } } props.children = childArray; } if (type && type.defaultProps) { var defaultProps = type.defaultProps; for (propName in defaultProps) { if (props[propName] === undefined ) { props[propName] = defaultProps[propName]; } } } if (__DEV__) { if (key || ref) { if ( typeof props.$$typeof === 'undefined' || props.$$typeof !== REACT_ELEMENT_TYPE ) { var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; if (key) { defineKeyPropWarningGetter(props, displayName); } if (ref) { defineRefPropWarningGetter(props, displayName); } } } } return ReactElement( type, key, ref, self, source, ReactCurrentOwner.current, props, ); };
官方有更详尽的讲解:https://facebook.github.io/react/docs/react-api.html#createelement