React源码学习
2018-04-12
##Virtual DOM模型
Virtual DOM模型组成:
- 标签名
- 节点属性: 样式, 属性和事件等
- 子节点
- 标识ID
1
2
3
4
5
6
7{
tagName: "div",
properties: {
style: {}
},
children: {},
key: 1,
Virtual DOM节点分类
- ReactElement
- ReactComponentElement
- ReactDOMElement
- ReactFragment
- ReactText
- ReactElement
创建React 元素
通过JSX创建的虚拟元素最终会被Babel编译成调用React的createElement方法。
1
2
3
4
5
6
7
8
9const Nav, Profile;
// 原始JSX
const app = <Nav color="blue"><Profile>click</Profile></Nav>;
// 转译后
const app = React.createElement(
Nav,
{color:"blue"},
React.createElement(Profile, null, "click")
)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
43ReactElement.createElement = function(type, config, children) {
// 初始化参数
var propName;
var props = {};
var key = null;
var ref = null;
var self = null;
var source = null;
// 如果存在config, 则提取里面的内容
if ( config != null ){
ref = config.ref === undefined ? null : config.ref;
key = config.key === undefined ? null : config.key;
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// 复制其他config的内容到props
for (propName in config) {
if (config.hasOwnProperty(propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)){
props[propName] = config[propName];
}
}
}
// 处理children, 全部挂载到props的children属性上,如果只有一个参数, 直接赋值给children,否则合并处理
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];
}
props.children = childArray;
}
// 如果某个 prop 为空且存在默认的 prop, 则将默认的 prop 赋值给当前prop
if ( type && type.defaultProps ){
var defaultProps = type.defaultProps;
for (propName in defaultProps) {
if ( typeof props[propName] === "undefined" ){
props[propName] = defaultProps[propName];
}
}
}
}
创建组件入口
1 | function instantiateReactComponent(node, parentCompositeType) { |
创建文本组件
1 | var ReactDOMTextComponent = function(text){ |
DOM 标签组件
`
javascript
_createOpenTagMarkupAndPutListeners: function(transaction, props) {
var ret = ‘<’ + this._currentElement.type;
// 拼凑出属性
for ( var propKey in props) {
var propValue = props[propKey];
if (registrationNameModules.hasOwnProperty(propKey)) {
// 针对当前的节点添加事件代理
if (propValue) {
enqueuePutListener(this, propKey, propValue, transaction);
}
} else {
if (propKey === STYLE) {
if (propValue) {
// 合并样式
propValue = this._previousStyleCopy = Object.assign({}, props.style);
}
propValue = CSSPropertyOperations.createMarkupForStyles(propValue, this);
}
// 创建属性标识
var markup = null;
if (this._tag != null && isCustomComponent(this._tag, props)){
markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
}
if (markup) {
ret += ' ' + markup;
}
}
}
// 对于静态页面, 不需要设置 react-id, 节省大量字节
if (transaction.renderToStaticMarkup) {
return ret;
}
// 设置 react-id
if (!this._nativeParent) {
ret += ‘’ + DOMPropertyOperations.createMarkupForRoot();
}
ret += ‘’ + DOMPropertyOperations.createMarkupForID(this._domID);
return ret;
}