当前位置:react
浏览其它
Hello World
下面的示例都是基于webpack的
react: 16.9.0
react-dom: 16.9.0
学习一个框架先从最简单的示例做起,比如下面的示例:
1 | import React from 'react'; |
JSX
如果我们使用
webpack
来开发react
应用,如何需要使用JSX
,我们需要引入以下代码:1
import React from 'react';
如果你引入了这段代码,
babel
会自动将JSX
解析成如下形式:1
2
3
4
5React.createElement(
'p',
null, // 这个参数代表JSX的props
'test'
)所以说需要导入
React
来支持JSX
的解析。具体
babel
是怎么编译的,查看这个在线演示
研究重点
至此,我们发现两个需要研究的重点
- 第一个是
react-dom
中的render
方法。 - 第二个是
react
中的createElement
方法。
下面我们来一个个看:
准备工作
- 先
clone
一下react
的仓库。 - 源码是使用
flow
写的,最好build
一下,拿最后生成的es5
文件来研究源码,flow
版本有一些webpack
的变量和参数,很难找,不清晰,而且依赖引用太多,跳跃性太强。
react/createElement
- 我们只看这个示例执行的时候
createElement
跑过的分支,整理如下:1
2
3function createElementWithValidation(type = 'p', props = null, children = 'test') {
return createElement.apply(this, arguments);
}
如果有多个
children
,会使用React.createElement
层层嵌套:如<p><a>test</a></p>
,会被解析成:React.createElement('p', null, React.createElement('a', null, 'test'))
- createElement:为了方便查看,直接将参数携带过来
1 | function createElement(type = 'p', config = null, children = 'test') { |
- 很简单,最后会返回这样的执行函数:
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
29var ReactElement = function (
type = 'p',
key = null,
ref = null,
self = null,
source = null,
owner = null,
props = { children: 'test' }
) {
const element = {
$$typeof: Symbol.for('react.element'),
type: 'p',
key: null,
ref: null,
props: { children: 'test' },
_owner: null,
_store: {
validated: false
},
_self: null,
_source: null,
};
// 这里有个小细节,freeze方法相当于浅冻结,所以需要对属性中的对象再次冻结
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
return element;
};
react-dom/render
现在我们知道其实最后执行的代码是这样的:
1 | ReactDOM.render( |
源码
- 话不多说:找到
build/node_modules/react-dom/cjs/react-dom.development.js
render
1 | function (element, container, callback) { |
legacyRenderSubtreeIntoContainer
1 | function legacyRenderSubtreeIntoContainer( |
拆分一下
legacyCreateRootFromDOMContainer
fiberRoot
,也就是root._internalRoot
,也就是rootContainer._internalRoot
,也就是legacyCreateRootFromDOMContainer
执行过后返回的对象里面的那个_internalRoot
属性updateContainer
unbatchedUpdates
getPublicRootInstance
- ok,一个个来。
legacyCreateRootFromDOMContainer
1 | // 第一步:格式化了一下`AppContainerDom`,移除了一些不必要的`dom`节点 |
结果
通过上面的步骤可以看到,最终legacyCreateRootFromDOMContainer
返回的是一个root
的实例,ROOTINSTANCE
就是legacyRenderSubtreeIntoContainer
中的fiberRoot
:
1 | { |
updateContainer
1 | function updateContainer( |
发现错误?想参与编辑?
在 GitHub 上编辑此页!
更新于:2019-10-22 16:10:82