brain-store

数据仓容器,数据存取

Usage no npm install needed!

<script type="module">
  import brainStore from 'https://cdn.skypack.dev/brain-store';
</script>

README

brain-store

一个抽象的 OOP 数据仓库,以 IOC 思想来管理数据的注册和读取,它很抽象,如果你要在 React 中,这个时候你可以借助 mobx 与 brain-store 结合来管 理数据,它只是一个数据仓库管理方案,只管理数据注册和数据正确读取,本身数据属性不具备响应式数据特性,如果你需要在 react,vue,angular 等 框架中应用,你还需要结合其框架本身特性来做处理

数据归类

通常我们对数据所应有场景做了一些简单归类,例如跟随应用整个生命周期的Application类型,基于路由的History类型,基于路由的数据,在路由 push 到不同页面时,我们都有一份页面自身独有的状态数据,它不受其他页面操作干扰,也不于其他页面状态产生依赖,在页面回退后,会自动销毁状态, 降低内存消耗。

什么是状态管理模式(认识状态管理)?

让我们从一个简单的 angular 计数应用开始:

import React from 'react';
export class AppComponent extends React.Component {
  count: number = 0;
  handleIncrement() {
    this.count++;
  }
  render() {
    <div onClick={this.handleIncrement.bind(this)}>{this.increment}</div>;
  }
}

这个状态自管理应用包含以下几个部分:

  • state,驱动应用的数据源;
  • view ,以声明方式将 state 映射到视图;
  • actions,响应在 view 上的用户输入导致的状态变化。

以下是一个表示“单向数据流”理念的极简示意: store-img 但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容 易被破坏:

  • 多个视图依赖于同一状态。
  • 来自不同视图的行为需要变更同一状态。
    对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者 通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置, 任何组件都能获取状态或者触发行为!

另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,我们的代码将会变得更结构化且易维护。

什么情况下我应该使用 brain-store?

虽然 brain-store+mobx 可以帮助我们管理共享状态,但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。如果您不打算开发大型单页应用,使 用 brain-store 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 brain-store。

use

npm install brain-store --save
or
yarn add brain-store -S

定义数据状态类型基类

Application类型(默认)

/* 定义基类*/
import Store, { StoreModules } from 'brain-store';
export default class StoreBase extends Store {
  static meta = {
    ...Store.meta,
    namespace: project.name,
  };
}
@StoreModules('UserListStore')
class UserListStore extends StoreBase {
  payloadModel = '';
}

ui-store 详情场景见数据归类介绍

import { action, computed, observable } from 'brain-store';
import { resource, StoreModules } from 'brain-store';
const User = resource('PMS/User');
/* UI基类*/
class UiStoreBase extends Store {
  static meta = {
    ...StoreBase.meta,
    lifecycle: Lifecycle.History,
    namespace: `${StoreBase.meta.namespace}.ui`,
  };
}
@StoreModules('UserListStore')
class UserListUiStore extends UiStoreBase {
  name = 'default';
}

eventScopes

当你 store 拆分的比较细的时候,当执行某个事件操作需要通知多个 store 中数据更新,这个时候我们通过在事件函数中直接调用各个 store 方法进行更 新操作,这虽然能解决,但显然不算是比较好的解法,这个时候我们可以定义一个事件触发器,当触发器中某个操作执行时,在需要执行响应动作的 store 中注入特定事件即可,例如下

import { resource, StoreModules } from 'brain-store';
const User = resource('PMS/User');
interface IUserInfo {
  userName: string;
  age: number;
}
const manage = new StoreManage();
const user = resource('PMS/User') as IResource;
@StoreModules('UserListStore')
class UserListStore extends StoreBase {
  static meta = {
    ...StoreBase.meta,
    eventScopes: [user],
  };
  userInfo: IUserInfo = (null as unknown) as IUserInfo;
  onEvent(event: IResourceEvent<IUserInfo>) {
    if (typeof event.payload === 'object') {
      this.userInfo = event.payload;
    }
  }
}

@StoreModules('UserEditStore')
class UserEditStore extends StoreBase {
  static meta = {
    ...StoreBase.meta,
    eventScopes: [user],
  };
  userInfo: IUserInfo = (null as unknown) as IUserInfo;
  triggerEvent(payload) {
    this.context.dispatch(user.created, payload);
  }
  onEvent(event: IResourceEvent<IUserInfo>) {
    if (typeof event.payload === 'object') {
      this.userInfo = event.payload;
    }
  }
}
const payload = { userName: 'xiaoming', age: 22 };
let listState: InstanceType<typeof UserListStore> = manage.getState(UserListStore, true);
let editState = manage.getState(UserEditStore, true);
editState.triggerEvent(payload);

contextTypes

在使用 store 时候,经常遇到不同 store 之间需要获取其他 store 实例,这个时候就可以使用它了

interface IUserInfo {
  userName: string;
  age: number;
}
interface IContext {
  app: AppStore;
}

//@ts-ignore
class StoreBases extends Store<IContext> {
  static meta = {
    ...Store.meta,
    namespace: 'pms',
  };
}
@StoreModules('UserListStore')
//@ts-ignore
class UserListStore extends StoreBases {
  static meta = {
    ...StoreBase.meta,
    contextTypes: { app: AppStore },
  };
  userInfo: IUserInfo = (null as unknown) as IUserInfo;
  getContextAppStore() {
    return this.context.app;
  }
}
const manage = new StoreManage();
let state = manage.getState(UserListStore, true);

let appStates = manage.getState(AppStore);
let appStore = state.getContextAppStore();

in brain-store-react to use

import React from 'react';
import Store, { bind ,inject} from 'brain-store';
import {observable} from 'mobx'
@StoreModules('UserListStore')
//@ts-ignore
class UserListStore extends Store {
  @observable userName=''
}
@bind({ store: UserListStore })
export default class User extends React.Component {
  @inject(UserListStore)
  userListStore!:UserListStore
  render() {
    null;
  }
}

Licensing

MIT license