用了幾個月的redux,現在回過來總結一下。
剛開始用的時候遇到一個比較大的疑問,就是如何設計redux的store中的state樹,這應該是我在使用redux中最大的一個疑問,阻擋了我前進的腳步,經過一段時間的研究,我這里給大家用非常通俗易懂的方式說一說我的疑問,以及我是如何解決的。
當初主要的疑問是:
1.state樹是按照頁面划分
2.還是按照數據庫中的表划分
第一種就是把每個頁面當成一個業務模塊,實際上這也是比較流行的一種做法,有很多公司是這么做的,比如你可以像下面這樣初始化你的store
module.exports = function() { return { common: { isFetching: false },
profile: {
},
list: { },
edit: {
},
home: {
}
}
}
這種方式的優點就是模塊與模塊之間互相獨立,不會相互影響,每個頁面維護自己的reducer,並且只在store中存入該頁面展示或者變化的最小數據,使用起來很方便,不太需要關心其他模塊的緩存數據,比較符合redux設計的初衷(並不是用來做一個前端數據庫),但這種方法有個致命的缺點,就是store中數據的同步問題和冗余問題。假如一個列表頁面的數據依賴於另一個編輯頁面的操作,在編輯頁面,改變了數據,這時候數據庫里面的數據已經被改變了,但這時候列表頁面和編輯頁面的state是獨立的,列表頁面state節點下的數據並沒有改變,退回到列表展示頁,數據並不會發生變化,這就有問題了,而且同一份數據出現在多個節點下,也會有數據冗余的問題。
要讓依賴的列表頁面也產生同步的更新,這里有四種做法:
1.每次進入列表頁面去數據庫刷新store(如果你做的是一個用戶端App顯然不會這么干,只可能在第一次進入的時候才會載入數據,第二次應該就不會發請求了,立即從store中拿出緩存數據,否則性能和體驗太差,PC端后台倒是無所謂)
2.編輯完保存后dispatch一個或多個action,去改變所有依賴到這條數據的頁面的state(相對還是比較可靠的辦法,前提是依賴的頁面很少,如果是一個龐大的系統,每次新增加一個頁面,你就需要去修改派發action的代碼,太麻煩了,除非建立一個完備的事件系統,所有依賴到這條數據的頁面都監聽一個事件,只要一編輯,就觸發所有的事件,更新自己的state節點),如果是這種情況,可以考慮看一看 rxjs
3.編輯完后除了更新數據庫中的數據,在前端這邊什么都不做,返回列表頁,先取出緩存數據展示,等到頁面DidMount之后發一個請求,不要出loading圖,檢查一下數據是否被更新過,如果是,拉取最新數據並更新store,如果不是,那就不變
4.列表頁和編輯頁共用一個state數據節點,列表頁只存必要顯示的字段,點擊進入編輯頁,根據列表頁的記錄id讀取更詳細的信息,編輯保存完成后,更新到這個state節點(這種方法其實采用的就是按數據庫表划分的辦法,統一數據源,關於統一數據源格式,可以看一看 normalizr )
注意:沒有人告訴過你,用了redux必須通篇要用store中的state,redux作者也沒有這么講過,比較好的做法是結合react組件自己的state和store中的state一起使用。
第二種就是按照數據庫中的表划分,比如你可以像下面這樣初始化你的store
module.exports = function() { return { common: { isFetching: false }, companies: { }, users: { }, events: { } } }
這種方法可能比較適合單頁應用,比如(trello,coding.net),把store當成數據庫使,增刪改查都維護這一個store,作為前端數據源,保證前端數據源和后端數據庫同步,並且保證了操作的及時反饋,適合對用戶體驗要求較高的場景,缺點就是前端不像后端,除了model數據,還有業務數據,臨時狀態數據,不能簡單的用數據庫的思路去設計store,如果是這樣,那么為什么不用前端數據庫呢?為啥還要用redux來多此一舉,redux本質上是用來管理數據狀態的。
所以,我認為還是按照頁面來划分,但應該把第二種方法的思路結合進來。
在此之前,先要認清哪些數據應該被放到store,如果是臨時數據,不需要緩存的,我們應該用react自己的state去維護狀態,而不是丟進store。如果該數據需要緩存,但只被一個頁面依賴了,那么放進該頁面節點下的state。如果該數據需要緩存,被多個頁面依賴了,那么我們應該將它提出來,放到一個公共state節點下。
redux作者的意思大概就是,對於store中的state樹,躺着用,站着用,跪着用,想怎么用怎么用,並沒有明確規定必須怎么用,只要自己用的舒服,解決你自己的特殊場景就可以了。