以下内容纯属个人理解,有错误欢迎评论纠正以及讨论
从最简单的例子开始
下面这个例子是最简单的 单纯的渲染一个hello world 点击变成 Hi world. 从render开始一点点看看react 到底干了啥:)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./react.js"></script>
<script src="./react-dom.js"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
class Hello extends React.Component {
state={
text:'Hello'
}
change() {
this.setState({
text:'Hi'
})
}
render() {
return React.createElement('div',{onClick:()=>this.change()}, `${this.state.text} ${this.props.toWhat}`);
}
}
ReactDOM.render(
React.createElement(Hello, { toWhat: 'World' }, null),
document.getElementById('root'),
function(){
console.log('render callback',this)
}
)
</script>
</html>
React.DOM.render
源码
function render(element, container, callback) {
if (!isValidContainer(container)) {
{
throw Error( "Target container is not a DOM element." );
}
}
{
var isModernRoot = isContainerMarkedAsRoot(container) && container._reactRootContainer === undefined;
if (isModernRoot) {
error('You are calling ReactDOM.render() on a container that was previously ' + 'passed to ReactDOM.createRoot(). This is not supported. ' + 'Did you mean to call root.render(element)?');
}
}
return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
}
注解
- element: react element
- container: 文档root节点
- callback: 执行完成之后回调 this指向instance 比如示例 指向
<Hello />
这个函数干了啥?
- 判断container是不是空的
- 判断是不是绑在document.body下了 react会提示最好不要这么做
- 判断一下callback参数的合法性
- 判断一下container._reactRootContainer是否存在来确定是不是第一次mount
- 判断一下root里面是不是干净的 不是就清除掉
上面的都不重要。。。最关键的是调用了 legacyRenderSubtreeIntoContainer
legacyRenderSubtreeIntoContainer
源码
function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
{
topLevelUpdateWarnings(container);
warnOnInvalidCallback$1(callback === undefined ? null : callback, 'render');
} // TODO: Without `any` type, Flow says "Property cannot be accessed on any
// member of intersection type." Whyyyyyy.
var root = container._reactRootContainer;
var fiberRoot;
if (!root) {
console.log('第一次渲染')
// Initial mount
// ❤️ 创建fiberroot ❤️
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
fiberRoot = root._internalRoot;
// ❤️ 处理callback ❤️
if (typeof callback === 'function') {
var originalCallback = callback;
callback = function () {
var instance = getPublicRootInstance(fiberRoot);
originalCallback.call(instance);
};
} // Initial mount should not be batched.
// ❤️ 采取同步运行 ❤️
unbatchedUpdates(function () {
updateContainer(children, fiberRoot, parentComponent, callback);
});
} else {
fiberRoot = root._internalRoot;
if (typeof callback === 'function') {
var _originalCallback = callback;
callback = function () {
var instance = getPublicRootInstance(fiberRoot);
_originalCallback.call(instance);
};
} // Update
updateContainer(children, fiberRoot, parentComponent, callback);
}
return getPublicRootInstance(fiberRoot);
}
注解
这个函数创建了一个FiberRoot 大概长下面这样
这期间react 还劫持了所有的事件 listenToAllSupportedEvents
getPublicRootInstance
在浏览器环境下返回的就是containerFiber.child.stateNode,本例子中<Hello />
到这里初始化阶段差不多结束了
初始化阶段(流程图)
一句话总结
在这个过程中 react 新建了一个fiberRoot,关联上了dom root和fiberRoot,劫持了所有的events。