在现代Web开发中,状态管理是构建可维护和可扩展应用的关键部分。BobX是一个类似于MobX的库,专为Bobril应用设计,用于管理应用的状态。BobX由Boris Letocha(Quadient)开发,使用TypeScript编写,非常适合Bobril应用的需求。它采用观察者模式,其中状态(stores)是可观察的主题,而Bobril组件则是观察者。
BobX入门
将通过创建一个简单的TODO应用来开始。首先,确保计算机上已经安装了Bobril构建工具。按照第一篇文章中的步骤进行安装。现在,可以开始一个新的项目,或者使用来自Bobril构建工具GitHub仓库的预定义骨架simpleApp。
以下示例将使用simpleApp。要获取包括所有所需组件的最终代码,请下载完整的示例代码。
BobX应用架构
BobX使用TypeScript的实验性特性——装饰器。要允许使用装饰器,请在package.json文件的bobril/compilerOptions部分添加以下参数:
{
"bobril": {
"compilerOptions": {
"experimentalDecorators": true
}
}
}
接下来,将BobX添加到应用中:
npm i bobx --save
创建BobX状态管理
首先,将创建一个简单的BobX状态管理,它包含与Bobflux变体相同的数据。这个状态管理将在store.ts文件中定义:
import { observable } from 'bobx';
class TodoStore {
@observable todoName: string = '';
@observable private _todos: string[] = [];
get todos(): string[] {
return this._todos;
}
addTodo(): void {
if (this.todoName.trim().length === 0) return;
this._todos.push(this.todoName.trim());
this.todoName = '';
}
}
export const todoStore = new TodoStore();
在上面的代码中,使用了@observable装饰器来创建todoName和_todos字段的getter/setter,并跟踪这些字段。当这些字段在Bobril组件的任何渲染函数中使用时,将自动调用b.invalidate(ctx)函数,更新特定的上下文。
使用BobX构建页面
现在,已经准备好在TODO应用的页面上使用BobX了。src/mainPage.ts文件将如下所示:
import * as b from 'bobril';
import { button } from './components/button';
import { textbox } from './components/textbox';
import { p } from './components/paragraph';
import { h1 } from './components/header';
import { todoStore } from './store';
export const mainPage = b.createComponent({
render(_ctx: b.IBobrilCtx, me: b.IBobrilNode): void {
me.children = [
h1({}, 'TODO'),
p({}, [
textbox({ value: todoStore.todoName, onChange: newValue => todoStore.todoName = newValue }),
button({ title: 'ADD', onClick: () => todoStore.addTodo() })
]),
todoStore.todos.map(item => p({}, item)),
p({}, `Count: ${todoStore.todos.length}`)
];
}
});
组件的定义不是本文的主题,因此可以使用附带的源代码中的定义。可以看到页面直接从store模块导入状态管理。textbox和button组件在其onChange和onClick回调中使用状态管理中定义的操作,以便视图中的用户交互触发操作调用。最后,在render函数的末尾是一个映射的todos数组,用于显示待办事项名称。
全局状态管理
全局状态管理是定义和使用状态的一种方式,但不是唯一的方式。可以在组件的init方法中直接实例化页面状态,并将其通过数据传递给其子组件。也可以为组件的内部数据创建上下文状态,这些数据想要跟踪。
上下文状态的示例:
class CtxStore extends b.BobrilCtx
状态优化
除了纯粹的observable函数来定义可观察属性外,有时不想跟踪对象的所有属性。让来看看其他可能的方式:
- observable.deep - 默认的observable方式。它递归地装饰给定对象的所有定义属性,使其可观察(跟踪)。当属性包含具有定义原型的对象时,递归停止。
- observable.ref - 只跟踪对象的引用。内部属性的任何更改都不会触发渲染。
- observable.shallow - 这种变体将跟踪给定对象的引用、其属性,但不会跟踪更多。例如,数组将跟踪其引用、其内容,但不会跟踪其项的内容。
- observable.map - 可以使用这个函数创建一个动态键控的可观察映射。
- computed - 可以在类属性的任何getter上使用这个装饰器,以声明性地创建计算属性。计算值是可以从未有状态或其他计算值派生的值。