Reflux和React全家桶的一些想法

Reflux怎么玩?

Reflux的action應(yīng)該全權(quán)負(fù)責(zé)async到服務(wù)器的數(shù)據(jù)處理,尤其是數(shù)據(jù)的卸載。

Reflux的store應(yīng)該分為最少3種:

  • 最基本的:數(shù)據(jù)型
  • 少量:broadcast廣播型
  • 通道:tunnel型

一、數(shù)據(jù)型是基本數(shù)據(jù)的:

store用來存數(shù)據(jù),這些數(shù)據(jù)在邏輯上與用戶有關(guān),比如用戶的基本信息,存數(shù)據(jù)的store在以引用mixins的方式被引入react組件的時(shí)候需使用Reflux.connect方法,這樣,react組件初始化時(shí)會(huì)調(diào)用store的getInitialState和react組件的getInitialState方法合并起來提供數(shù)據(jù)到react組件的state里。注意,這個(gè)地方組件調(diào)用store的getInitialState,但是store可能早已存在于內(nèi)存里了,這個(gè)時(shí)候store里如果已有數(shù)據(jù)(比如用戶信息已經(jīng)從服務(wù)器獲取到了),就應(yīng)該把這些數(shù)據(jù)直接從store的getInitialState里返回回去,而不是再?gòu)姆?wù)器獲取一次。所以,一個(gè)方便的react組件對(duì)接數(shù)據(jù)型store時(shí)的代碼是這樣的:
store:

/* 這樣的store的基本行為模式是: */
/* 1. 初始化(init)里生成默認(rèn)數(shù)據(jù) */
/* 2. 某react的組件獲取數(shù)據(jù)的時(shí)候走到getInitialState,去后臺(tái)獲取數(shù)據(jù)(僅一次) */
/* 3. 之后由于用this.data.pristine置位過,數(shù)據(jù)會(huì)直接從getInitialState流到react組件,而不會(huì)再去服務(wù)器獲取 */
/* P.S. 謹(jǐn)慎使用或者干脆禁用開發(fā)者從component上自己調(diào)用服務(wù)器獲取數(shù)據(jù) */
const SomeDataStore = Reflux.createStore({
  /* 這個(gè)只是給react組件用的,調(diào)一次執(zhí)行一次,對(duì)store而言可不是一輩子就一次 */
  getInitialState: function() {
    if(this.pristine) { // 放這里調(diào)action,還用一個(gè)變量控制住,只發(fā)一次后臺(tái),而且是按需發(fā)后臺(tái)
      SomeDataAction.getSomeData() // 這里其實(shí)會(huì)有async的bug,少數(shù)情況下會(huì)有多個(gè)action發(fā)出,但業(yè)務(wù)邏輯明確組件結(jié)構(gòu)明確的時(shí)候確實(shí)不會(huì)bug
    }
    // getInitialState是react組件初始化時(shí)必須調(diào)用的方法,這里給組件提供數(shù)據(jù)
    // 但是這個(gè)方法并不是store初始化自己的方法(這個(gè)坑好痛)
    return this.data
  },
  /* init才是store的生命周期好嘛 */
  init: function() { // 這才是Store初始化的方法,這里一次性生成初始化數(shù)據(jù)
    this.pristine = true // 增加這個(gè)字段來表達(dá)當(dāng)前store的數(shù)據(jù)是否已從服務(wù)器獲取過
    this.data = {
      userName: ‘unknown’,
      userId: -1,
    },
  },
  // 數(shù)據(jù)過來后,記得 this.pristine = false
})

react component:

/* 別忘了,掛載store的組件是smart component (container) */
const SomeComponent = React.reactClass({
  mixins: [ Reflux.connect(SomeDataStore, ’someData') ], // 這個(gè)mixins會(huì)把SomeDataStore返回的數(shù)據(jù)掛到this.state.someData處
  getInitialState: function() {
    // 你還是可以用getInitialState來初始化一些界面內(nèi)部的數(shù)據(jù)的,只是不要和store里的getInitialState沖突就好
    return { uiData: ‘德瑪西亞!' }
  },
})

二、少量broadcast廣播型store:

比如,好多http錯(cuò)誤,很煩,真不想讓他們跟數(shù)據(jù)混在一起,于是有這個(gè)想法:所有http錯(cuò)誤讓一個(gè)store去捕捉,捕捉后trigger出去的時(shí)候掛一個(gè)type字段,哪個(gè)組件想報(bào)錯(cuò),就去監(jiān)聽(是的,這是async,發(fā)起的component要先Reflux.listenTo到)這個(gè)store的數(shù)據(jù),用type過濾后報(bào)錯(cuò)給用戶。(所以如果你明知道自己觸發(fā)了http請(qǐng)求,但是并沒打算報(bào)錯(cuò)到用戶那里,完全可以不監(jiān)聽這個(gè)store)

const SOME_TYPE = 'some_type'

// maybe NotificationStore?
var NotifyStore = Reflux.createStore({
  init: function() {
    this.listenTo(Action.fetch.success, this.triggerWrapper(SOME_TYPE, true))
    this.listenTo(Action.fetch.error, this.triggerWrapper(SOME_TYPE, false))
  },
  triggerWrapper: function(source, success) {
    return function(resp) {
      this.trigger({
        source: source,
        success: success && resp.Success,
        code: resp.ErrorCode,
        msg: resp.ErrorMsg, // TODO: 這里要“或”一個(gè)非200的http response
      })
    }
  },
})

三、通道型的store:

這個(gè)store類型我其實(shí)還沒有使用過,但是在看同事寫某個(gè)翻頁(yè)列表的時(shí)候看到的:有這么一些數(shù)據(jù)并不需要存放在數(shù)據(jù)型的store里,它們只對(duì)一個(gè)界面有意義,獲取一次就拋棄了,沒必要存著。怎么辦呢?Reflux和Redux的最大區(qū)別也許也在這里:在Redux里,我們想把所有state存在store里,甚至組件只用一個(gè)render方法就寫出來了,可是Reflux里基本只存了邏輯上的數(shù)據(jù),組件的“小狀態(tài)”基本都是封裝在組件內(nèi)部的,而這部分“只對(duì)一個(gè)界面有意義”的數(shù)據(jù)正是這種“小狀態(tài)”。所以這個(gè)時(shí)候,畢竟所有http請(qǐng)求都習(xí)慣性封裝進(jìn)了action,所以做一下tunnel類的store,數(shù)據(jù)從action的async過來,經(jīng)store轉(zhuǎn)手交給react組件,不保存(沒必要保存),所以稱之為tunnel(隧道/通道).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容