React 是一个非常流行的前端框架,它提供了一种声明式的编程方式来构建用户界面。但是,React 的工作原理并不容易理解,更不用说从底层实现一个类似 React 的框架了。
幸运的是,Facebook 开源了一个 npm 包叫做 react-reconciler,它提供了一些底层的构建块来实现自己的 React-likes 框架。在本篇文章中,我们将会了解 react-reconciler 的使用教程,深入探讨其原理,并提供一些示例代码。
什么是 React 协调器?
在了解 react-reconciler 之前,我们需要先了解 React 的协调器(也称为调和器)。React 协调器是 React 的核心算法,用于将应用程序状态映射到视图层级。在 React 库中,我们通常使用 ReactDOM 在 Web 上渲染界面。ReactDOM 实现了针对 Web 平台的协调器,它负责将 React 元素(Element)转换为 DOM 元素。
但是,React 还可以使用同样的编程模型来构建其他类型的 UI,例如移动应用程序、三维游戏、VR 和 AR 应用程序等。为了支持这些场景,React 团队提供了一个通用的协调器接口,即 react-reconciler。这个接口包含了一些基础算法和钩子,您可以实现自己的协调器,并在特定的平台上运行。
如何使用 react-reconciler?
我们来看一个基础的例子,如何使用 react-reconciler 构建一个简单的文本组件。
首先,我们需要安装 react-reconciler:
npm install react-reconciler
然后,我们创建自己的协调器。在这个例子中,我们称之为 MyRenderer:
import { Reconciler } from 'react-reconciler'; const MyRenderer = Reconciler({ // Your custom implementation });
接下来,我们定义我们的组件,这个例子只是一个简单的文本组件:
const TextComponent = { type: 'text', props: null, };
最后,在我们自定义的实现中,我们需要为 MyRenderer 添加一些方法,例如 createInstance、appendChild 等等。可以想象一下,这些方法称为 Reconciler Host Config,它们提供了外部环境和自定义的核心实现间的桥梁。
-- -------------------- ---- ------- ----- ---------- - ------------ -- --- -- --------------- ----- ------ ---------------------- ------------ ---------------------- - - -- ----- --- ------- - ------ ---------------------------- - ----- --- ------------------ --------- ----- - - ------ -- ------------------- ----- ---------------------- ------------ ---------------------- - - ------ ------------------------------ -- --------------------------- ------ - ---------------------------------- -- ------------------------- - ------ ------ -- ------------------ - ------ ----- -- ------------------ - ------ ----- -- -- --- -- ---展开代码
现在,我们可以使用 react-reconciler 渲染我们的组件了:
const root = MyRenderer.createContainer(document.getElementById('root'), false); const textNode = MyRenderer.createInstance(TextComponent); MyRenderer.appendChild(root, textNode); MyRenderer.updateContainer('Hello, world!', root, null);
完成了这个例子,我们现在可以更深入地探讨一下 react-reconciler 的 API 和原理了。
React Reconciler API
Reconciler(options)
Reconciler 函数是我们构建自己的协调器的入口点。它接受一个 options 对象,它的属性列表如下:
createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle)
: 这个方法创建一个新的实例,表示特定类型的组件或原生控件。在浏览器中,这意味着创建一个 DOM 元素。React 使用这个方法跟踪组件结构,维护组件之间的关系,等等。createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle)
: 这个方法创建一个新的文本节点实例,用于表示 DOM 中的文本。React 将所有文本视为特殊类型的组件,因此如果您在组件中使用文本,React 将会调用这个方法来创建文本节点。appendChild(parentInstance, child)
: 这个方法添加一个子元素到父元素中。在 React 中,这个方法表示将子元素添加到父元素的 children 属性中。removeChild(parentInstance, child)
: 这个方法删除子元素从父元素中。React 使用这个方法来管理协调器内部的组件结构,以确保正确的协调和更新。insertBefore(parentInstance, child, beforeChild)
: 这个方法将一个子元素插入到另一个子元素的前面。在 React 中,这通常在兄弟组件之间移动元素时使用。finalizeInitialChildren(parentInstance, type, props, rootContainerInstance, hostContext)
: 这个方法获取一个组件的 props,并在组件被创建后调用。我们可以在这里修改初始化后的属性数据。例如,如果我们要为新组件设置默认值,则可以在这个方法中查找和确认所需的值。prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, hostContext)
: 当组件更新时,React 会调用此方法,该方法允许我们比较 props 和以前的 props,并确定是否需要更新。如果我们确定组件不需要更新,则返回 null。commitUpdate(instance, updatePayload, type, oldProps, newProps, internalInstanceHandle)
: 当组件需要更新时,React 将会调用此方法来执行真实的更新。在这里,我们可以使用之前计算出的更新内容,将其反映到真实的 DOM 上,或者在自定义的目标平台上反映更新。prepareForCommit(containerInfo)
: 在 React 开始更新组件之前,我们可以在此方法中执行一些准备工作。例如,如果我们需要向自定义平台发送异步任务,则可以在这里处理并等待任务完成。resetAfterCommit(containerInfo)
: 当 React 完成更新并已经成功渲染了 DOM(或自定义平台)时,此方法将会被调用。我们可以在这里进行一些在更新后运行的任务(例如动画等)。
Reconciler.createContainer(containerInfo[, isConcurrent[, hydrate]])
createContainer 方法创建一个新的协调器根节点。协调器节点对应了应用程序中的一个根 DOM 节点(或自定义平台等其他环境)。
containerInfo
: 一个容器信息对象,该对象包含与 an 的 container 相关的特定信息。在 Web 上,这个就是一个 DOM 节点。isConcurrent
: 切换到 Concurrent 模式。hydrate
: 执行 Hydrate 模式。
Reconciler.updateContainer()
updateContainer 方法触发协调器更新。它类似于 ReactDOM.render 方法,但是它允许我们在多个时刻更新组件(例如,当应用程序状态改变时)。
示例代码
下面是一个完整的例子,其中我们将使用 react-reconciler 实现自己的协调器和组件。这个例子中,我们将在一个 WebGL 视口上绘制一个简单的方块。
-- -------------------- ---- ------- ------ - ---------- - ---- ------------------- ----- ---------- - ------------ -- ------ ------------------------------ ------------- - ----- -- - ----------------- -- ----- --- ------ - --- --- -------- -------------- --- - ---- ------ - ----------- - --------- ---- ---- ----- ------------ - ------ - -- - ---- ------ - ------------ - --------- ---- ---- ----- - - -- --------------- ---------------- --- ---------------- ----- -- -- -- ---- -------------------- ------ ---------------------- ------------ ----------------------- - ----- -- - ------------------------- -- ----- --- --------- - ------ - ----- ----- ------ ----------- -- --- -- --- -------- ------------------------------ --------------- ------------------------------------- -- - ----- --- ------------------ --------- ---- ---------- -- -- ---- ----------------------- ----- --------- --------- ---------------------- ------------ - ------ --------- -- -- ------ ---------------------- -------------- ----- --------- --------- ----------------------- - -- ----- --- --------- - -------------- - -------------- -- --- -- --- - -- -- ----- --------------------------- ------ --- -- --------- --------------------------- ------ --- -- ------ ------------------------ ---------------------- ------------ ----------------------- --- -- ----- ------------------------- - ------ ------ -- -- ---- ------------------ --- -- ---- ------------------ --- -- ---- -- ----------- --------------------------- - ------ ------ -- -- ---------- ---- ------ ----------- --- -------- - -- -- ----------------- - -- -- ----------- ----------------- ----- -------------------- ------ ------------------ ------ --- -- -- ----- --- ----- ------ - --------------------------------- ----- -- - --------------------------- -- -- ---------- --- ----- ---- - ---------------------------- --- --- --- -- -- ------ -- ----- ------ - --------------------------- ----- --------- ------ --- -- --- --- -- -- ------ ------- ---------------------------- -------- -- -- ---------- --- ------------------------------ ----- ----- ------ -------- ----------------- --------- --------- - ----- -- - ---------------------------------- ------------------- ---------- --------------------- ----- -- - ------------------------------------ ------------------- ---------- --------------------- ----- ------- - ------------------- ------------------------ ---- ------------------------ ---- ------------------------ -- --------------------------------- ---------------- - ----- ------------- ----------------------------------- - ------ -------- - -------- ---------------- ----- - ----- ------ - ------------------ ------------------------------ -------- ------------------------------ ----- ---------------- ------ ------- -展开代码
这些代码将在 WebGL 上绘制一个简单的方块。这只是一个开始,并不算完整的实现,但它向您展示了如何使用 react-reconciler 实现自己的协调器,以及如何在自定义平台上渲染组件。
结论
React-reconciler 是 React 之外最为核心的一部分,它是在 React 基础上做自定义渲染、组件化UI以及Flash/flex等跨平台方向的催生器,这样在任何需要构建基于React编写的可视化程序的场景下都可以使用React即免于反复深入底层实现。在我们的实践中,我们可以使用 react-reconciler 创建自己的协调器。我们使用 MyRenderer 来实现绘制 WebGL 图形的协调器,来解释 react-reconciler 并提供了示例的深度文章。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/115274