共计 2504 个字符,预计需要花费 7 分钟才能阅读完成。
大家好,我卡颂。
React
能够看作是三局部的组合:
scheduler
,调度器,用于调度工作reconciler
,协调器,用于计算工作造成的副作用renderer
,渲染器,用于在宿主环境执行副作用
这三者都是独立的包,咱们我的项目里引入的 ReactDOM
能够看作是以下三局部代码打包而成:
scheduler
的次要逻辑reconciler
局部逻辑ReactDOM renderer
的次要逻辑
本文会教你如何基于官网的reconciler
,实现迷你ReactDOM
。
本文参考 Hello World Custom React Renderer
我的项目初始化
通过 CRA
建设我的项目(或用已有我的项目):
create-react-app xxx
新建 customRenderer.js
,引入react-reconciler
并实现初始化:
// 本文应用的 reconciler 版本是 0.26.2 | |
import ReactReconciler from 'react-reconciler'; | |
const hostConfig = {}; | |
const ReactReconcilerInst = ReactReconciler(hostConfig); |
其中 hostConfig
就是宿主环境的配置项。
最初,customRenderer.js
导出一个蕴含 render
办法的对象:
export default {render: (reactElement, domElement, callback) => { | |
// 创立根节点 | |
if (!domElement._rootContainer) {domElement._rootContainer = ReactReconcilerInst.createContainer(domElement, false); | |
} | |
return ReactReconcilerInst.updateContainer(reactElement, domElement._rootContainer, null, callback); | |
} | |
}; |
在我的项目入口文件,将 ReactDOM
换成咱们实现的CustomRenderer
:
import ReactDOM from 'react-dom'; | |
import CustomRenderer from './customRenderer'; | |
// 替换 ReactDOM | |
CustomRenderer.render( | |
<App />, | |
document.getElementById('root') | |
); |
实现 ReactDOM
接下来咱们实现 hostConfig
配置,首先填充空函数防止利用报错:
const hostConfig = { | |
supportsMutation: true, | |
getRootHostContext() {}, | |
getChildHostContext() {}, | |
prepareForCommit() {}, | |
resetAfterCommit() {}, | |
shouldSetTextContent() {}, | |
createInstance() {}, | |
createTextInstance() {}, | |
appendInitialChild() {}, | |
finalizeInitialChildren() {}, | |
clearContainer() {}, | |
appendInitialChild() {}, | |
appendChild() {}, | |
appendChildToContainer() {}, | |
prepareUpdate() {}, | |
commitUpdate() {}, | |
commitTextUpdate() {}, | |
removeChild() {} | |
} |
留神这里惟一一个 Boolean
类型的配置项 supportsMutation
,他示意宿主环境的API
反对mutation
。
这是 DOM API
的工作形式,比方 element.appendChild
、element.removeChild
。如果是Native
环境则不是这种工作形式。
接下来咱们来实现这些API
。
实现 API
这些 API
能够分为如下几类。
初始化环境信息
getRootHostContext
与 getChildHostContext
用于初始化上下文信息。
生成 DOM 节点
createInstance
用于创立 DOM 节点createTextInstance
用于创立文本节点
能够将 createTextInstance
实现如下:
createTextInstance: (text) => {return document.createTextNode(text); | |
} |
要害逻辑的判断
shouldSetTextContent
用于判断组件的 children
是否是 文本节点
,实现如下:
shouldSetTextContent: (_, props) => {return typeof props.children === 'string' || typeof props.children === 'number';},
DOM 操作
appendInitialChild
用于插入 DOM
节点,实现如下:
appendInitialChild: (parent, child) => {parent.appendChild(child); | |
}, |
commitTextUpdate
用于扭转 文本节点
,实现如下:
commitTextUpdate(textInstance, oldText, newText) {textInstance.text = newText;},
removeChild
用于删除子节点,实现如下:
removeChild(parentInstance, child) {parentInstance.removeChild(child); | |
} |
当实现了所有 API
后,页面就能失常渲染了:
残缺实现的 Demo
地址见:残缺 Demo 地址
总结
通过本文的学习,咱们实现了一个繁难ReactDOM
。
如果你想在任何能够绘制 UI
的环境应用 React
,都能够利用react-reconciler
实现该环境下的React
。
比方,Introduction To React Native Renderers 教你如何在 Native
环境实现React
。
欢送退出人类高质量前端框架群,带飞