本文开始于2019年2月15日,还在不断更新中。。
希望通过摘录和解释react最关键的代码,帮助我自己和其他人理解react源码
你不可能只阅读文章就理解react,你必须阅读react源码才能理解react :)
这里可能有很多错误和漏洞,欢迎在评论区指正,一切以源码为准。
react最关键的代码
操作dom
浏览器在内存里存了一堆数据,是一个树,叫做dom,修改dom里的数据会触发浏览器重绘界面,如果频繁的触发浏览器重绘,效率比较低。
react在内存里存了类似的一堆数据,也是一个树,叫做virtual dom,react应用在收到事件(点击,网络。。。)后先修改virtual dom, 修改virtual dom只修改virtual dom树里的数据,不会触发重绘。
react 隔一段时间找出virtual dom和dom的区别,批量的把这些区别应用到dom上,以此提升性能。
但归根结底,要修改dom,才能让浏览器重绘,才能让用户看到界面改变,操作dom的代码在这两个文件:
packages/react-dom/src/client/ReactDOMComponent.js
packages/react-dom/src/client/ReactDOMHostConfig.js
从下面的函数实现里可以找到react最终调用dom的api的地方,为方便阅读,代码有删改,此处只略举几例,完整的代码请阅读react-dom源码
// 以下代码在ReactDOMComponent.js
// 获取dom对象
function getOwnerDocumentFromRootContainer(
rootContainerElement: Element | Document,
): Document {
return rootContainerElement.nodeType === DOCUMENT_NODE
? (rootContainerElement: any)
: rootContainerElement.ownerDocument;
}
// 新建Element
export function createElement(
type: string,
props: Object,
rootContainerElement: Element | Document,
parentNamespace: string,
): Element {
...
if (type === 'script') {
const div = ownerDocument.createElement('div');
div.innerHTML = '<script><' + '/script>'; // eslint-disable-line
const firstChild = ((div.firstChild: any): HTMLScriptElement);
domElement = div.removeChild(firstChild);
} else if (typeof props.is === 'string') {
domElement = ownerDocument.createElement(type, {is: props.is});
} else {
domElement = ownerDocument.createElement(type);
if (type === 'select' && props.multiple) {
const node = ((domElement: any): HTMLSelectElement);
} }
} else {
domElement = ownerDocument.createElementNS(namespaceURI, type);
}
...
}
// 新建TextNode
export function createTextNode(
text: string,
rootContainerElement: Element | Document,
): Text {
return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(
text,
);
}
// 以下代码在ReactDOMHostConfig.js
// append 子元素
export function appendChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
parentInstance.appendChild(child);
}
网友评论