65.9K
CodeProject 正在变化。 阅读更多。
Home

Bobril - VI - BobX 应用程序商店管理

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2017 年 8 月 12 日

CPOL

4分钟阅读

viewsIcon

13578

对 bobril 的 BobX 应用程序商店管理的解释

引言

第二篇文章中,我们使用 bobflux 框架创建了一个简单的 ToDo 应用程序。 在本文中,我们将学习如何使用新框架 BobX 以更简单的方式创建此类应用程序。

背景

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 模块导入存储。

textboxbutton 组件在其 onChangeonClick 回调函数中使用在 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 创建的文章
© . All rights reserved.