当我们开始将状态引入 UI 组件时,通常很容易做这样的事情:
Svelte 中的简单计数器示例:
<script> let count = $state(0); </script> <button onclick={() => count++}> clicks: {count} </button>
我们在这里使用 Svelte,但同样的问题也适用于任何 UI 框架。
我们立即将状态逻辑与组件紧密耦合 - 增量功能直接编码在模板中。
通过此设置,我们无法在以下位置重用计数器逻辑:
我们也无法在不渲染组件的情况下测试计数器逻辑。如果组件具有与其耦合的其他功能,则不可能隔离计数器逻辑。
将状态逻辑与 UI 组件分开,以便可以独立实现和测试。这将使逻辑更加可重用,UI 组件只需要监听状态变化并渲染。考虑以下几点:
<script> import { RxCounter } from './RxCounter'; const [count, { increment }] = RxCounter(); </script> <button onclick={increment}> Count: {$count} </button>
查看 StackBlitz 上的完整示例
如果将上面的示例与我们原来的示例进行比较,计数器的所有逻辑现在都封装在 RxCounter 中(我们稍后将展示实现)。
count 是一个发出新计数状态的 RxJS Observable。 increment 是 UI 可以调用来调用状态更改的操作方法。
Svelte 有一个很好的内置方式来订阅模板中的可观察量,如 $count 模板变量所示。在任何 UI 框架中订阅可观察对象并不是非常困难,并且许多框架都有 API 来帮助完成此任务。
信息和免责声明:我们将使用作者创建的 Reactables API。它是一个状态管理解决方案,利用 RxJS 使响应式编程变得更容易。
获取Reactables核心包并创建RxCounter。
npm 我@reactables/core
import { RxBuilder } from '@reactables/core'; export const RxCounter = () => RxBuilder({ initialState: 0, reducers: { increment: (count) => count + 1, }, });
RxBuilder 返回一个 Reactable。
Reactable 是一个元组,其第一项是发出状态更改的 RxJS Observable,第二项是用于触发状态更新的操作方法的字典。
状态是反应性,这意味着状态通过其reducer函数响应变化。当接收到由 UI 触发的增量操作时,可反应 会做出反应 及其可观察对象会发出新状态。
注意 RxCounter 现在与视图层完全解耦,可以在任何 UI 框架中使用!
为了测试 Reactable,我们订阅它的可观察状态并调用它的操作方法来测试它的行为。我们可以断言 observable 的发出值与所需的行为相匹配。
这可以通过 RxJS 内置的 Marble 测试来完成。
<script> let count = $state(0); </script> <button onclick={() => count++}> clicks: {count} </button>
通过与视图隔离的状态逻辑,我们还可以扩展 RxCounter 的功能并创建一个具有双倍计数能力的 RxDoubleCounter。
<script> import { RxCounter } from './RxCounter'; const [count, { increment }] = RxCounter(); </script> <button onclick={increment}> Count: {$count} </button>
查看 StackBlitz 上的完整示例
直接在 UI 组件中实现状态逻辑会使逻辑更难重用和测试。
我们可以使用 Reactables 对状态逻辑进行反应式编程并单独测试它。这会产生一个反应式状态逻辑单元,在视图层和逻辑层中都具有高度可重用性。
我们在这里做了一个简单的反例,但是Reactables对于更复杂的状态管理场景(即数据获取、表单等......)是可扩展和可组合的。查看文档以了解更多信息!
以上是通过反应式编程实现可重用、可扩展和可测试的状态逻辑。的详细内容。更多信息请关注PHP中文网其他相关文章!