自己造一个ReactDOM
大家好,我卡颂。
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(
,
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
。【自己造一个ReactDOM】欢迎加入人类高质量前端框架群,带飞
推荐阅读
- 一个人的旅行,三亚
- 尽力
- 一个小故事,我的思考。
- 一个人的碎碎念
- 七年之痒之后
- 我从来不做坏事
- 异地恋中,逐渐适应一个人到底意味着什么()
- 牛人进化+|牛人进化+ 按自己的意愿过一生
- 别怪生活,自己作的!
- 迷失的世界(二十七)