接上:“如何运行react源码” juejin.cn/post/692970…
因为在react项目中,都是从ReactDOM.render开始挂载组件到根节点的,因此render方法应该是学习的一个入口,所以打算从这个方法开始入手;
// others code ...
<div id="container"></div>
// others code ...
ReactDOM.render(
<h1>Hello World!</h1>,
document.getElementById('container')
);
从官网上找到render方法的用法
zh-hans.reactjs.org/docs/react-…
从官网上可以看到render方法的使用方法和功能说明;
找到render方法源码
从react-dom源码中的package.json文件中,我们可以找到入口文件为index.js,从index.js中就可以看到render方法,如下图;
源码:
编译后的代码在
react-dom.development.js中可以找到:
分析render方法
render的功能是“在提供的 container 里渲染一个 React 元素,并返回对该组件的引用(或者针对无状态组件返回 null)。”
语法为
ReactDOM.render(element, container[, callback])
源码中可以看到接收的参数,
element, 是一个ReactElement对象,babel会将jsx语法的dom编译后经过createElement方法生成一个ReactElement对象;container:放element的容器,容器节点里的所有 DOM 元素都会被替换;callback:回调函数
render(
element: React$Element<any>,
container: Container,
callback: ?Function,
)
render函数中调用了isValidContainer,isContainerMarkedAsRoot,legacyRenderSubtreeIntoContainer三个方法
isValidContainer
在调用render方法时,首先会通过
isValidContainer方法来判断传入的container是不是一个dom元素,判断方法根据dom的nodeType属性处理。
nodeType 属性返回节点类型。
-
如果节点是一个元素节点,nodeType 属性返回 1。
-
如果节点是属性节点, nodeType 属性返回 2。
-
如果节点是一个文本节点,nodeType 属性返回 3。
-
如果节点是一个注释节点,nodeType 属性返回 8。
-
该属性是只读的。
具体nodeType值可以点击链接查看:nodeType
源码中,已经定义好常量ELEMENT_NODE,TEXT_NODE等类型值
isContainerMarkedAsRoot
// 生成随机值
const randomKey = Math.random()
.toString(36)
.slice(2);
// 拼接出key
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
// 判断节点是否有internalContainerInstanceKey
export function isContainerMarkedAsRoot(node: Container): boolean {
return !!node[internalContainerInstanceKey];
}
legacyRenderSubtreeIntoContainer
将dom节点渲染到container中,这个里面感觉逻辑比较多,后期单独对其中的方法拆开学习。
源码:
render中调用该方法:
legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
疑问
render方法是react-dom的入口,单独看方法比较简单,+ isValidContainer只是判断是不是正确的节点,这个大家都容易明白;
isContainerMarkedAsRoot判断是不是被标记为root的容器,什么时候会被标记?为什么被标记?legacyRenderSubtreeIntoContainer里面包含了很多方法,整个render的核心应该就是它了,react-dom的其他逻辑是不是都是从这个方法开始被调用的?
练手项目
根据中文网提到的相关操作,可以将react,react-dom打包,直接通过dev.html加载运行,为了后期方便学习,我直接将用到的文件复制到新的空项目中,github地址:github.com/dai12544737…
如果有想要一起学习的可以直接clone代码,项目中source目录下的文件是打包后直接复制过来的,本人不会修改该目录中内容,packages下是react没有打包前的代码,可以对比学习。
打包后的代码适合本地debug调试,查看react运行机制,可以参考react源码查看。
各位善良的大佬如果发现我学习的方法有问题或者出现了错误,有时间麻烦帮忙指出下,非常感谢~