redux store設(shè)計(jì)

store用于存儲(chǔ)應(yīng)用數(shù)據(jù)茧痒,表達(dá)應(yīng)用狀態(tài)疮跑。設(shè)計(jì)store的步驟大致有兩步:

  1. 梳理應(yīng)用數(shù)據(jù)都有哪些
  2. 設(shè)計(jì)這些數(shù)據(jù)在store中的組織結(jié)構(gòu)

梳理數(shù)據(jù)

首先說明一下食寡,這里說的數(shù)據(jù)辟汰,有時(shí)可能包含一些狀態(tài)典格。
數(shù)據(jù)大概有幾類:

  1. 界面需要展示的數(shù)據(jù)
  2. 為了獲取1中的數(shù)據(jù)岛宦,而需要的數(shù)據(jù)
  3. 界面相關(guān)的狀態(tài)數(shù)據(jù)
  4. 其他

第一類不用說肯定要放到store里,指需要在界面展示的業(yè)務(wù)數(shù)據(jù)
第二類是可能會(huì)讓人迷惑的耍缴,比如請(qǐng)求分頁數(shù)據(jù)時(shí)的參數(shù)砾肺,請(qǐng)求到第幾頁了
第三類指正在加載,下拉刷新中等界面動(dòng)畫之類的進(jìn)行狀態(tài)防嗡,或者是用戶的交互狀態(tài)变汪,比如用戶是否是第一次打開界面,或者有沒有點(diǎn)擊過某個(gè)按鍵
第四類比較特殊蚁趁,我遇到一個(gè)就是數(shù)據(jù)的初始化狀態(tài)裙盾,即數(shù)據(jù)是否已經(jīng)初始化

其他的情況暫時(shí)沒有遇到

我理解的判斷一個(gè)數(shù)據(jù)是否應(yīng)該放入store的方法是:
判斷這個(gè)數(shù)據(jù)所代表的含義是否和界面狀態(tài)無關(guān),如果和界面無關(guān)就放入store他嫡,有關(guān)就單獨(dú)維護(hù)番官。

比如 分頁的頁數(shù)代表的是業(yè)務(wù)數(shù)據(jù)的頁數(shù)和界面無關(guān),就放入store钢属,
加載中代表的是界面正在laoding徘熔,和界面有關(guān),就不放入store
用戶是否點(diǎn)擊過某個(gè)按鈕也是界面上的操作淆党,就不放入store
初始化狀態(tài)是代表數(shù)據(jù)是否有初始化酷师,和界面無關(guān),就放入store

設(shè)計(jì)store結(jié)構(gòu)

store的結(jié)構(gòu)都是樹狀結(jié)構(gòu)
大致的原則是

  1. 按模塊劃分染乌,比如同一個(gè)界面相關(guān)的數(shù)據(jù)放一個(gè)樹節(jié)點(diǎn)上
  2. 盡量扁平山孔,比如一級(jí)節(jié)點(diǎn)是模塊,二級(jí)節(jié)點(diǎn)就是具體數(shù)據(jù)
  3. 顯式聲明使用不變量類型荷憋, 比如直接用HashPMap TreePVetor(pcollection庫中)饱须,而不用Map List

按模塊劃分是為了方便維護(hù),不同的模塊相互不會(huì)沖突台谊,也方便不同的模塊監(jiān)聽數(shù)據(jù)
扁平是為了減少嵌套的層級(jí)蓉媳,數(shù)據(jù)狀態(tài)一目了然
使用不變量是基本要求,而顯示聲明類型锅铅,是讓使用數(shù)據(jù)的人酪呻,可以明確的知道這個(gè)是不能修改的

細(xì)節(jié)

  1. 是否需要初始化狀態(tài) 看情況,主要是為了解決耗時(shí)的初始化產(chǎn)生的前后界面不一致
  2. 葉子節(jié)點(diǎn)的數(shù)據(jù)需要注意盐须,如果是復(fù)雜的數(shù)據(jù)結(jié)構(gòu)玩荠,比如自定義類,或者HashPMap贼邓,在使用的時(shí)候需要考慮空指針
  3. 到底是把復(fù)雜的數(shù)據(jù)扁平化用多個(gè)葉子節(jié)點(diǎn)阶冈,還是用一個(gè)復(fù)雜數(shù)據(jù)結(jié)構(gòu)和一個(gè)葉子節(jié)點(diǎn),各有利弊塑径,扁平化會(huì)使每個(gè)reducer的邏輯簡單女坑,但是代碼較大,而且同一個(gè)action可能有好多reducer都要處理统舀,有可能漏reducer處理匆骗,一個(gè)葉子節(jié)點(diǎn),這個(gè)reducer的邏輯會(huì)很復(fù)雜誉简,但是代碼相對(duì)集中碉就,如果你有能力有條理的寫復(fù)雜代碼可以用一個(gè)葉子節(jié)點(diǎn),如果不行闷串,就扁平化瓮钥,每個(gè)reducer的代碼邏輯都很簡單,容易上手烹吵。

實(shí)例分析

背景

我們的界面是多種數(shù)據(jù)一起刷新碉熄,由于接口是復(fù)用的,就沒有新定義接口年叮,在刷新時(shí)是單獨(dú)調(diào)用每個(gè)數(shù)據(jù)接口獲取數(shù)據(jù)具被,結(jié)果就有三種:全部成功、部分成功只损、全部失敗一姿,需求是有數(shù)據(jù)就展示數(shù)據(jù),有數(shù)據(jù)有失敗的時(shí)候跃惫,Toast提示失敗叮叹,全部失敗時(shí),界面展示異常界面爆存。

設(shè)計(jì)

因?yàn)閿?shù)據(jù)請(qǐng)求失敗蛉顽,是應(yīng)用數(shù)據(jù)的狀態(tài),就把這個(gè)數(shù)據(jù)放入store了先较,一般失敗都有錯(cuò)誤碼和錯(cuò)誤提示信息携冤,我就把這兩個(gè)字段都放入store了悼粮。
類似下面

{
  "status" : 0,
  "msg" : "Success"
}

界面綁定數(shù)據(jù)的邏輯如下

if(hasData()) {
  // show data
  if(status != 0) {
    // show Toast with msg
  }
} else {
  // show error view with status
}

第一個(gè)bug

在每次刷新單個(gè)數(shù)據(jù)時(shí),如果一直是相同的錯(cuò)誤曾棕,status和msg不會(huì)變扣猫,導(dǎo)致只有第一次刷新提示失敗,后續(xù)刷新就沒有錯(cuò)誤提示了翘地。
我當(dāng)時(shí)覺得這個(gè)問題在于status和msg沒有變申尤,所以不會(huì)觸發(fā)數(shù)據(jù)變化監(jiān)聽,于是我修改了store

{
  "status" : 0,
  "msg" : "Success",
  "counter" : 0
}

每次reducer處理衙耕,如果是失敗昧穿,counter就加1,讓數(shù)據(jù)產(chǎn)生變化橙喘,從而觸發(fā)監(jiān)聽时鸵,進(jìn)行錯(cuò)誤提示

第二個(gè)bug

每次界面(Fragment)重新加載,重新綁定數(shù)據(jù)時(shí)渴杆,如果原來的狀態(tài)是有部分?jǐn)?shù)據(jù)寥枝,有失敗,就會(huì)在Fragment每次啟動(dòng)時(shí)磁奖,彈Toast囊拜。
為什么會(huì)這樣呢?我當(dāng)時(shí)覺得原因在status和msg其實(shí)是上次的請(qǐng)求失敗比搭,并不是當(dāng)下的請(qǐng)求失敗冠跷,所以我在Fragment里記錄counter,綁定數(shù)據(jù)前身诺,先讀取一次蜜托,在綁定時(shí)做判斷,邏輯如下

// 在綁定之前 先獲取counter
int msgCounter = counter;

// 綁定邏輯
if(hasData()) {
  // show data
  if(status != 0 && msgCounter != counter) { // counter值不一樣 說明這是新的錯(cuò)誤霉赡,應(yīng)該提示
    // show Toast with msg
    msgCounter = counter
  }
} else {
  // show error view with status
}

反思

這兩個(gè)bug橄务,我用這種方式是解決了,但是我的解決方式對(duì)嗎穴亏?

先看第二個(gè)bug蜂挪,status和msg是上次請(qǐng)求的結(jié)果,但是實(shí)際上數(shù)據(jù)也是上次請(qǐng)求的結(jié)果嗓化,在不重新刷新的情況下棠涮,上一次請(qǐng)求的數(shù)據(jù),就是當(dāng)下的數(shù)據(jù)刺覆,綁定當(dāng)下的數(shù)據(jù)在邏輯上沒有問題严肪。

但是為什么會(huì)出bug呢,關(guān)鍵在于彈錯(cuò)誤提示其實(shí)是一次需求,不需要多次彈驳糯,但是狀態(tài)記錄在store里篇梭,導(dǎo)致每次綁定都會(huì)彈Toast。

我開始反思status和msg到底應(yīng)該不應(yīng)該放入store酝枢,按照前面說的判斷方法很洋,異常狀態(tài)這個(gè)數(shù)據(jù)代表的業(yè)務(wù)含義就是應(yīng)用的狀態(tài),比如沒有網(wǎng)絡(luò)隧枫,退出登錄,其實(shí)和界面無關(guān)谓苟,所以應(yīng)該放入store官脓,沒有錯(cuò)。

然后我開始注意到其實(shí)我判斷異常狀態(tài)需要的只有status一個(gè)字段涝焙,沒有msg字段卑笨,狀態(tài)判斷不會(huì)有任何問題,我發(fā)現(xiàn)msg字段只是因?yàn)槲覀円恢币粊礤e(cuò)誤碼和錯(cuò)誤信息是放一起的仑撞,所以我才把msg字段放入store的赤兴。

那我們單獨(dú)對(duì)msg字段進(jìn)行判斷,msg字段表示的業(yè)務(wù)含義是錯(cuò)誤狀態(tài)在界面上的提示信息隧哮,它是和界面相關(guān)的桶良,沒有界面,也就不需要展示沮翔,就不需要msg字段陨帆,所以msg字段不應(yīng)該放入store!
msg字段其實(shí)屬于前面說的第三類數(shù)據(jù):界面相關(guān)的狀態(tài)數(shù)據(jù)采蚀。

那需求又該怎樣實(shí)現(xiàn)呢疲牵?前面的兩個(gè)bug又該如何修改呢?

// Store結(jié)構(gòu)
{
  "status" : 0
}
// 刷新數(shù)據(jù)
dispatcher.dispatch(new RrefreshAction(new RefreshListener(){
  void refreshResult(String msg){
    // 如果msg不為空榆鼠,即刷新有失敗的情況纲爸,需要彈Toast
    // show Toast with msg
  }
}));

// 數(shù)據(jù)綁定
if(hasData()) {
  // show data
} else {
  // show error view with status
}

這樣修改之后妆够,前面兩個(gè)bug自然就不存在了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末识啦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子责静,更是在濱河造成了極大的恐慌袁滥,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灾螃,死亡現(xiàn)場離奇詭異题翻,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門嵌赠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來塑荒,“玉大人,你說我怎么就攤上這事姜挺〕菟埃” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵炊豪,是天一觀的道長凌箕。 經(jīng)常有香客問我,道長词渤,這世上最難降的妖魔是什么牵舱? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮缺虐,結(jié)果婚禮上芜壁,老公的妹妹穿的比我還像新娘。我一直安慰自己高氮,他們只是感情好慧妄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著剪芍,像睡著了一般塞淹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上紊浩,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天窖铡,我揣著相機(jī)與錄音,去河邊找鬼坊谁。 笑死费彼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的口芍。 我是一名探鬼主播箍铲,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鬓椭!你這毒婦竟也來了颠猴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤小染,失蹤者是張志新(化名)和其女友劉穎翘瓮,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裤翩,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡资盅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呵扛。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡每庆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出今穿,到底是詐尸還是另有隱情缤灵,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布蓝晒,位于F島的核電站腮出,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏芝薇。R本人自食惡果不足惜利诺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剩燥。 院中可真熱鬧,春花似錦立倍、人聲如沸灭红。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽变擒。三九已至,卻和暖如春寝志,著一層夾襖步出監(jiān)牢的瞬間娇斑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國打工材部, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毫缆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓乐导,卻偏偏與公主長得像苦丁,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子物臂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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