設計實現優雅修改redux數據流的一個庫

前言

首先呢~ 在分享前先貼上我寫的redux-chef源碼,你們若有興趣能夠閱讀:redux-chefgit

背景:麻煩的redux社區規範

在使用redux好久之後,有一天寫着寫着,忽然以爲actions/constants/reducers這一套東西顯得十分囉嗦(相信不少同窗有這種感受)github

好比看redux的官方實例: todomvc。簡簡單單一個todomvc,也寫出來很多樣板代碼。redux

哎呀好麻煩吶,我就想簡簡單單調用改個數據流而已,爲啥要我寫這麼這麼長的代碼?mvc

因而乎!聽聞社區裏的那個 dva 很強大,我點開官網看了看它的示例,受其啓發,忍不住也花了幾個小時寫了一個 redux-chef(不過自己和dva沒什麼關係,類似的地方也就只有model的設計了)來完成我優雅修改redux數據流的設想~app

什麼有趣的東西?一個主廚(Chef)!

那麼日常的redux,除了上述說的代碼樣板比較多以外,還有一個點也是修改同一個數據,須要跳躍好幾個文件,這也是蠻費心力的,我的感受!框架

通常來講,一個reducer關注的每每只是其維護的state。那麼其實能夠把每一個reducer維護的state、以及其全部的action維護在同一個model裏面誒dom

根據業務設計本身的model

首先根據業務場景定義本身的model(爲了節省空間,代碼省略了一部分),而後用redux-chef導出的kitchen煮一下(笑)。這樣的models數據就是通過主廚精心加工過的,能夠以後在業務代碼裏優雅調用了~函數

// models/index.ts
import { kitchen } from '../redux-chef';
const Cord = {
  namespace: 'cord',
  state: { x: 3, y: 4 },
  action: {
    update(x: number, y: number) {
      return { x, y };
    },
    setDoubleX: () => (state: any) => {
      return {
        ...state,
        x: state.x * 2
      }
    }
  },
  reducer: function (state: any, action: any) {
    //...
  }
};

const Points = {
  namespace: 'points',
  state: [],
  reducer: function (state: any, action: any) {
    //...
  }
};
export default kitchen({ Cord, Points });
複製代碼

備註:完整示例models代碼 -> github.com/soulizs/red…優化

而後在將這些加工後的models應用到咱們用redux建立的store裏,就能夠開始在應用代碼裏redux-chef設計的調用啦!spa

優雅又簡易的調用方式

示例使用redux-chef後的數據流調用方式以下:

// App.ts
import models from './models/index.ts';

function updateCord() {
  models.Cord.update(generateRandNum(), generateRandNum())
}

function setDoubleCordX() {
  models.Cord.setDoubleX();
}
// render
<Button onClick={updateCord}>update cord x & y</Button>
<Button onClick={setDoubleCordX}>double cord x</Button>
複製代碼

天吶,修改數據流只須要關注models裏action函數,而後在應用裏直接調用對應的model:models.Cord.setDoubleX();就完成了數據流的改動,而後將對應的state進行connect,即完成了更新後數據的讀取。

優雅的是,這種調用給應用開發者帶來了流程的簡化,只須要關注業務的開發,減小重複的樣板代碼~

備註:眼尖的同窗或許會發如今 Cord model裏面的這兩個actionupdatesetDoubleX有點不同。緣由是,setDoubleX因爲須要讀取model裏的state,因此設計成高階函數,用以自動讀取其對應model的state!

固然這種方式也提供了使用咱們自定義使用action的自由,在model.reducer會進行分發。以下示例代碼:

// actions/index.ts
import { dispatch } from '../redux-chef';
export function setCordX(x: number) {
  dispatch({
    type: constants.SET_CORD_X, x
  });
}

// App.ts
import { setCordX } from './actions/index.ts';
// render
<Button onClick={() => setCordX(generateRandNum())}>set cord x</Button>
複製代碼

新舊共存,毛問題~

redux-chef的設計哲學

好了使用方式上文都介紹了,其實redux-chef的設計也挺簡單的,主要是Chef(), dispatch(), cook(), kitchen(), Chef.apply()這四個API,有興趣的同窗閱讀一下源碼便可(也不長)。

簡單來講:

  • 自動聚合全部models的reducer返回給store應用
  • 若是調用了model.action,也就是說是這種操做姿式的話,models.Cord.setDoubleX();,會使用內部自定義的@@${__CHEF_INTERNAL_TYPE__}(${name})分發事件,本質上仍是分發。

  • 上文提到的,若是model.action須要使用自己的state做爲依賴計算的話,利用高階函數自動傳入state。

  • 沒什麼問題是不能用多一層抽象解決的!

小結

  1. 建議你們在看完此文後,拉下此倉庫運行一下看看!請點擊:redux-chef(注意是improve-reading分支)
  2. 不建議你們在生產環境使用redux-chef。因爲社區裏存在不少優秀的應用框架,好比 dva 等等。(備註:本人也只是純粹隨便敲敲而已,暫不發佈,也不作維護~

謝謝你們的閱讀!固然還有不少優化和設計的空間,你們若是有想法與建議,歡迎評論~

(爲何起這個名字 redux-chef?由於我常常在半夜敲代碼時感到飢餓...)

相關文章
相關標籤/搜索