項目地址:https://github.com/wooline/react-coat前端
// 僅需一個類,搞定 action、reducer、effect、loading class ModuleHandlers extends BaseModuleHandlers { @reducer protected putCurUser(curUser: CurUser): State { return {...this.state, curUser}; } @reducer public putShowLoginPop(showLoginPop: boolean): State { return {...this.state, showLoginPop}; } @effect("login") // 使用自定義loading狀態 public async login(payload: {username: string; password: string}) { const loginResult = await sessionService.api.login(payload); if (!loginResult.error) { this.updateState({curUser: loginResult.data}); Toast.success("歡迎您回來!"); } else { alert(loginResult.error.message); } } // uncatched錯誤會觸發@@framework/ERROR,監聽併發送給後臺 @effect(null) // 不須要loading,設置爲null protected async ["@@framework/ERROR"](error: CustomError) { if (error.code === "401") { this.dispatch(this.actions.putShowLoginPop(true)); } else if (error.code === "301" || error.code === "302") { this.dispatch(this.routerActions.replace(error.detail)); } else { Toast.fail(error.message); await settingsService.api.reportError(error); } } // 監聽自已的INIT Action,作一些異步數據請求 @effect() protected async ["app/INIT"]() { const [projectConfig, curUser] = await Promise.all([ settingsService.api.getSettings(), sessionService.api.getCurUser() ]); this.updateState({ projectConfig, curUser, }); } }
差別示例:使用強類型組織全部 reducer 和 effect
// Dva中常這樣寫 dispatch({ type: 'moduleA/query', payload:{username:"jimmy"}} }) //本框架中可直接利用ts類型反射和檢查: this.dispatch(moduleA.actions.query({username:"jimmy"}))
差別示例:State 和 Actions 支持繼承
// Dva不支持繼承 // 本框架能夠直接繼承 class ModuleHandlers extends ArticleHandlers<State, PhotoResource> { constructor() { super({}, {api}); } @effect() protected async parseRouter() { const result = await super.parseRouter(); this.dispatch(this.actions.putRouteData({showComment: true})); return result; } @effect() protected async [ModuleNames.photos + "/INIT"]() { await super.onInit(); } }
差別示例:在 Dva 中,由於使用 redux-saga,假設在一個 effect 中使用 yield put 派發一個 action,以此來調用另外一個 effect,雖然 yield 能夠等待 action 的派發,但並不能等待後續 effect 的處理:
// 在Dva中,updateState並不會等待otherModule/query的effect處理完畢了才執行 effects: { * query (){ yield put({type: 'otherModule/query',payload:1}); yield put({type: 'updateState', payload: 2}); } } // 在本框架中,可以使用awiat關鍵字, updateState 會等待otherModule/query的effect處理完畢了才執行 class ModuleHandlers { async query (){ await this.dispatch(otherModule.actions.query(1)); this.dispatch(thisModule.actions.updateState(2)); } }
差別示例:若是 ModuleA 進行某項操做成功以後,ModuleB 或 ModuleC 都須要 update 自已的 State,因爲缺乏 action 的觀察者模式,因此只能將 ModuleB 或 ModuleC 的刷新動做寫死在 ModuleA 中:
// 在Dva中須要主動Put調用ModuleB或ModuleC的Action effects: { * update (){ ... if(callbackModuleName==="ModuleB"){ yield put({type: 'ModuleB/update',payload:1}); }else if(callbackModuleName==="ModuleC"){ yield put({type: 'ModuleC/update',payload:1}); } } } // 在本框架中,可以使用ActionHandler觀察者模式: class ModuleB { //在ModuleB中兼聽"ModuleA/update" action async ["ModuleA/update"] (){ .... } } class ModuleC { //在ModuleC中兼聽"ModuleA/update" action async ["ModuleA/update"] (){ .... } }
本框架上手簡單react
8 個新概念:git
Effect、ActionHandler、Module、ModuleState、RootState、Model、View、Component
4 步建立:github
exportModel(), exportView(), exportModule(), createApp()
3 個 Demo,按部就班:typescript
入手:Helloworld進階:SPA(單頁應用)redux