Bobril - VI - BobX 应用程序商店管理
对 bobril 的 BobX 应用程序商店管理的解释
引言
在第二篇文章中,我们使用 bobflux 框架创建了一个简单的 ToDo 应用程序。 在本文中,我们将学习如何使用新框架 BobX 以更简单的方式创建此类应用程序。
- Bobril - I - 入门
- Bobril - II - Bobflux 应用程序架构
- Bobril - III - 本地化和格式化
- Bobril - IV - 路由
- Bobril - V - Bobril-build
- Bobril - VI - BobX 应用程序商店管理
- Bobril - VII - 组件和 TSX
背景
BobX 是一个类似 MobX 的库,用于管理 Boris Letocha (Quadient) 创建的应用程序商店。 它是用 TypeScript 编写的,适用于 bobril 应用程序的需求。 它使用观察者模式,其中商店是可观察的主题,而 bobril 组件是观察者。
开始吧
我们将再次创建一个简单的 TODO 应用程序。 首先,我们需要在计算机上准备好 bobril-build
。 按照第一篇文章中的步骤进行 bobril-build
安装。
现在您可以再次启动一个新项目,或者使用来自 bobril-build github 存储库的预定义骨架 simpleApp
。
以下示例将使用它。 要获取包括所有必需组件的最终代码,请下载完整的示例。
BobX 使用 TypeScript 的实验性功能 - 装饰器。 要允许使用装饰器,请将以下参数添加到 package.json 中的 bobril/compilerOptions 部分
"bobril": {
"compilerOptions": {
"experimentalDecorators": true
}
}
将 bobx 添加到应用程序
在应用程序文件夹的根目录下运行以下命令
npm i
npm i bobx --save
bb
商店
首先,我们将创建一个简单的 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();
在上面的代码中,您可以看到在字段 todoName
和 _todos
上使用了 @observable
装饰器。 此装饰器为这些字段创建了带有跟踪功能的 getter/setter。 它将导致跟踪这些字段。 当此类字段用于 bobril
组件的任何渲染函数中时,则在每次更改此字段时,将自动使用特定的 context
调用函数 b.invalidate(ctx)
。
使用 BobX 组合页面
现在,我们已经准备好一切,可以在 todo 应用程序的页面上使用。 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
回调函数中使用在 store
上定义的操作,因此来自视图的用户交互会启动操作调用。 最后,在 render
函数的末尾,是将 todos 映射到带有 todo 名称的 'p
' 标签的数组。
现在,我们可以在浏览器中打开应用程序,网址为 https://:8080,看看它是如何工作的。
Global 存储 是一种定义和使用存储的方式,但不是唯一的方式。
页面存储 可以直接在组件的 init
方法中实例化,并通过数据传递给其子组件。
上下文存储 可以创建为组件的组件上下文,用于您要跟踪的组件的内部数据。
上下文存储 的示例
class CtxStore extends b.BobrilCtx<IData> {
@observable someProperty: string = '';
constructor(data: IData, me: b.IBobrilCacheNode) {
super(data, me);
...
}
}
export const myComponent = b.createComponent<IData>({
ctxClass: CtxStore,
render(ctx: CtxStore) {
...
}
})
存储优化
不仅有纯 observable
函数来定义可观察属性。 有时,您不想跟踪对象的所有属性,所以让我们看看其他可能的方式
observable.deep
- 默认的observable
方式。 它装饰给定对象的所有已定义属性,使其可观察(被跟踪),并递归进行。 当属性包含具有定义原型的对象时,递归停止。observable.ref
- 仅跟踪对象的引用。 内部属性的任何更改都不会触发渲染。observable.shallow
- 此变体将跟踪给定对象的引用、其属性,但仅此而已。 因此,例如,将跟踪数组的引用及其内容,但不会跟踪其项目的 content。observable.map
- 您可以使用此函数创建动态键的可观察映射。computed
- 您可以在类的任何 getter 属性上使用此装饰器来声明性地创建计算属性。 计算值是可以从现有存储或其他计算值派生的值。
要获取更多信息,请参阅项目 github 页面
或 MobX 文档页面
历史
- 2017-08-12:为 bobx@0.11.0 创建的文章