Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

License

NotificationsYou must be signed in to change notification settings

dobjs/dob-refetch

Repository files navigation

dob-refetch 是基于 dob 封装的 dob 的一种实践方案。dob-refetch 类型完美,请求方式简单轻便。

npm versionnpm downloads

install

$ npm i -S dob-refetch

usage

引用方式

importconnect,{BaseModel,BaseStore,Provider,observable,useDebug}from"dob-refetch";

Store

在 Store 中,可以定义待监听的数据、以及改变数据的 action。每个 Store 都和一个 View 一一对应。

其中,AppProps 类型是该 Store 对应的 View 的 Props 类型

@observableclassAppStoreextendsBaseStore<AppProps>{num=1;addNum(num:number){this.num=this.num+num;}}
  • init 用对应 View 的 Props 初始化
@observableclassAppStoreextendsBaseStore<AppProps>{num=number;init(props:AppProps){this.num=props.num;}}
  • getProps 获取对应 View 的 Props
@observableclassAppStoreextendsBaseStore<AppProps>{num=number;addNum(){this.num=this.getProps().num+this.num;}}
  • BaseModel 使用 BaseModel 来做 refetch

BaseModal<返回值类型>(返回值初始值, 对应的请求方法);

如下代码所示,data 是 BaseModel 的实例,fetchData 是对应的请求方法。

其中,data 会自动用请求方法发送请求,并自动处理 loading、success、error,自动触发 rerender。并且,由于 data 对应的请求方法 fetchData 依赖了 this.num,因此当 this.num 改变之后,fetchData 会自动再次执行,触发 data 的更新及 rerender。

@observableclassAppStoreextendsBaseStore<AppProps>{num=1;addNum(num:number){this.num=this.num+num;}data=newBaseModel("");  @bindField("data")privatefetchData(){// dependencies;constnum=this.num;returnmockFetch("I am response data");}}

其中 fetchData 也支持 async await 的方式

  • inject 依赖注入

当需要全局通信是,可以在本地 Store 中,注入其它 Store 的实例,以进行通信。

@observableclassAppStoreextendsBaseStore<AppProps>{num=1;addNum(num:number){this.num=this.otherStore.num+num;}otherStore=this.inject(state=>state.otherStore);}

View

View 需要用 connect 来绑定,connect 第一个参数是从 GlobalState 拿到对应 Store 的 selector。

GlobalState 稍后介绍。

@connect<GlobalState>(state=>state.app)classAppextendsReact.Component<AppProps,any>{render(){const{ store, state}=this.props;constdata=store.data;// 使用全局 stateconstotherNum=state.other.num;return(<div>num:{store.num}<buttononClick={store.addNum.bind(null,3)}>addNum</button>{data.loading ?"loading..." :data.data}</div>);}}

Provider

  • GlobalState
// 与redux 的 combineRedux相似,可以随意组装 globalStateconstglobalState={app:AppStore,other:OtherStore};// 拿到 globalState 的类型typeGlobalState=typeofglobalState;
  • Provider
ReactDOM.render(<Providerstore={globalState}>{children}</Provider>,document.getElementById("app"));

devtool

useDebug();

如图:

图片

规范

import 路径

importconnect,{observable,// Store 基类BaseStore,// 自动请求功能BaseModel,// 类似于 combineReducer,但只做类型转换,不做实事。fixStoreType}from"dob-refetch";

Store 规范

@observableclassXStoreextendsBaseStore<XProps>{// 属性区  a='a';b='b';// 复杂属性区complicatedProp={a:'a'};/*   * 依赖注入   * 因为单实例的应用都会传到 Provider 里。所以所有的单实例都可以用如下方法注入其它单实例。   */  @inject(AStore)a:AStore;// get 方法区getcomputedName(){returna+b;}// constructor,在实例创建时,如果有逻辑写在这里。constructor(){}/**只在单实例中使用。*单实例中,父级组件willMount时,传入父级的props进行该store的实例初始化。*单实例的初始化使用init。动态实例使用constructor*/init(props:XProps){}// set 方法区changeA(){this.a=a;}// set 方法区可以使用 async awaitasyncchangeA(){awaitpromise1;returnvalue;}asyncchangeB(){// async 方法之间调用和传值constvalue=awaitthis.changeA();}}

以上属性、方法的排序,可以在 tslint members-order 进行配置。

注意:

  • store 中的属性,只能通过调用 store 方法来修改。如果直接用 store.a = 'a2'; 这种方式来修改,dob 会报错。

  • 一种方法是,把属性置为 private 。其优点是是外部既无法直接修改。但是其缺点也是无法读取该属性,可能需要自己写一些重复的 get 方法,比如有些业务直接读取原生数据的 case 不多,更多的是读取衍生数据,那么用这种方法非常优雅。这里用哪种方法,要视业务情况而定,没有固定规定。

Store 单实例

Store 规范不变。

View 规范如下:

@connect<GlobalState> (state =>state.a.b)classViewextendsComponent<Props>{}

Store 动态实例

含义

Store 实例在运行时动态生成。比如一个 TODOList 的 TODOListItemStore。onedata 中每个 Tab 的 Store。由于,我们的全局 Store 树始终是静态的,因此这些动态实例,可以动态挂载在 静态树的叶子节点上。

@observableclassTabStoreextendsBaseStore<TabStore>{  sql='';submitSql(){postSql.request({sql:this.sql}).then(()=>{message.success(...);},e=>{message.error(e.message||I18N.message.error);})}}@observableclassTabsextendsBaseStore<TabsProps>{tabItems=[]asTabStore[];createTab(tab:TabStore){this.tabItems.push(tab);}}// 静态全局 Store 树:constglobalStore={menu:MenuStore,header:HeaderStore,frame:FrameStore,tabs:TabStore});typeGlobalStore=ReturnState<typeofglobalStore>;

ReturnState 做了一件神奇的事情,转换之前,比如 menu 的类型是一个 Class 。转换之后,它是一个实例。可以通过源码了解一下原理。

规范

Store 规范不变。

View 规范如下:

区别是,connect 不需要任何参数。因为多实例的 Store 不应该绑定任何 store 示例,而是父级在 Props 中传入一个动态的 store,该 store 应该由对应的 Store 创建。

@connectclassViewextendsComponent<Props,xx>{render(){const{ store}=this.props.store;return ...;}}<Viewstore={newStore()}>

业务组件复用

怎样写可复用业务组件

// 不需要 @observableclassMyStoreextendsBaseStore<Props>{// Store 逻辑不变}// 不需要 @connectclassMyViewextendsReact.Component<Props,any>{// View 逻辑不变}

如何复用组件

@observableexportclassAStoreextendsMyStore{// 特殊逻辑}constAView=connect<GlobalState>(state=>state.a)(MyView);

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp