最近從 https://github.com/frontend9 上看了下博主對 redux 學習過程的一個分享 , 講解的很是仔細易懂 , 感興趣的建議從博主的 https://github.com/brickspert/blog/issues/22 案例中去逐個學習理解(動手敲) , 相信必定可以對 redux的使用有個完全的理解;html
咱們從中文文檔中能夠看到這樣的話:git
'隨着 JavaScript 單頁應用開發日趨複雜,JavaScript 須要管理比任什麼時候候都要多的 state (狀態)。 這些 state 可能包括服務器響應、緩存數據、本地生成還沒有持久化到服務器的數據,也包括 UI 狀態,如激活的路由,被選中的標籤,是否顯示加載動效或者分頁器等等'github
Redux 試圖讓 state 的變化變得可預測。這些限制條件反映在了 redux 的三大原則中ajax
1:單一數據源redux
2:state 是隻讀的緩存
3:使用純函數來執行修改服務器
假設你歷來沒有用過 redux, 拋棄這些名詞, 回到原始的開發模式。使用 ajax 從服務器請求數據, 根據數據生成 html片斷, 插入到指定的 dom節點。邏輯很簡單根本就不須要使用框架, 就能夠得到很好的開發和瀏覽體驗。框架
當單頁面模式推崇以後 , 全部的操做都在一個 html文件中去處理, 狀況變得複雜起來了。在一個頁面中你須要處理各個模塊的邏輯 , 你要不斷去處理數據的更新, 添加, 刪除; 這時候若是不對數據修改加以約束(隨處可見的修改, 跨頁面的修改等), 會難以追蹤到你的數據走向。frontend
尤爲是對於引用類型數據, 對某一處不經意的修改, 簡直會讓人崩潰(你不知道到底在哪裏做了修改, 可能就發生在某一個函數的調用中, 好比對形參 param.a = 1 這種操做)。dom
這時候也有人推出了深複製的解決辦法, 每次都是操做一個全新的對象, 對源數據不會形成任何影響, 思路固然沒錯. 可這距離咱們指望的結果: 對於數據的每一次修改都是可監測可控制的。仍是有些差距。
Redux 的推出可謂是一種很好的解決方案。正如 redux文檔自述中所言: Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理
正由於它堅持的三大原則
1. 單一數據源; 避免了咱們在各個模塊中去重複複製, 重複定義, 這對於整個應用的數據更新都會帶來麻煩; 要麼只在模塊內部去定義, 要麼定義在全局(單一數據源上), 不推薦在內部定義一個, 在全局又定義一個同一用途的數據;
2. state 是隻讀的, redux提供了惟一改變 state 的方法就是觸發 action; 它們只能表達想要修改的意圖,
3. 使用純函數來執行修改;
咱們來看一看執行修改的邏輯就明白了:
function changeCount(state={}, action){ switch(action.type) { case 'INCREMENT': return { ...state, count: state.count + 1 } default: return state } }
咱們對原狀態 state 沒有作任何修改, 只是返回了一個新的 state; 藉由此, 在處理邏輯時, 咱們能夠把應用上一次的 state, 和更新後的 state 都傳遞出去; 甚至咱們能夠改寫裏面的邏輯, 記錄下前幾回狀態值的修改;
始終記住 redux提供可預測化的狀態管理, 這就是它所作的工做。
/*********************** *************************************/
在之前本身去記錄應用狀態的作法多是這樣的;
function createStore (initData) { var APP_DATA = initData || {};
return { get: function (key) { return key ? APP_DATA[key] : APP_DATA; }, set: function (key, data) { APP_DATA[key] = data; } } } var Store = createStore(); function getUserInfo () { setTimeout(function () { var userInfo = { name: '張三', age: '23' }; Store.set('userInfo', userInfo); }, 100) } getUserInfo(); function validate () { return !!Store.get('userInfo'); } function submit () { var userInfo; if (validate()) { userInfo = Store.get('userInfo'); console.log(userInfo); } } setTimeout(submit, 300);
換做用 redux 可能得這樣
function createStore (reducer, initState) { var listeners = []; var store = initState; function getState () { return store; } function subscribe (listen) { listeners.push(listen) } function dispatch (action) { store = reducer(store, action); for(var i = 0; i < listeners.length; i++) { listeners[i]() } } return { getState: getState, subscribe: subscribe, dispatch: dispatch } } function reducer (state, action) { switch (action.type) { case 'SET_USERINFO': return { ...state, userInfo: action.data } default: return state; } } var Store = createStore(reducer, {}); function getUserInfo () { setTimeout(function () { Store.dispatch({ type: 'SET_USERINFO', data: { name: '張三', age: '23' } }); }, 100) } getUserInfo(); function validate () { return !!Store.getState().userInfo; } function submit () { var userInfo; if (validate()) { userInfo = Store.getState().userInfo; console.log(userInfo); } } setTimeout(submit, 300);
應該用什麼樣的方式去管理應用狀態 , 這個問題或許太寬泛沒法回答 , 我只能說踩過的一些坑 , 也是對以前的"錯誤作法"一些總結:
1. 賦值操做時要格外當心 , 尤爲是引用;
2. 避免兀餘的數據 , 這時咱們經常會定義些 "全局變量" , 來保存多個位置的相同信息。儘可能去約束脩改的行爲
3. 保護好你的應用數據 。不得已 能夠經過重置的手段還原到初始狀態。
/*********************** 補充 *************************************/
對於 redux 本身也存在些疑惑的地方 , 在下面暫且把它視做 redux 的缺陷吧
1. redux 的 action 分發機制: 在源碼中 action 被自頂往下層層傳遞 , 也就意味全部的下級狀態都會接受到消息 , 那也就可能存在 有多個下級狀態 同時作出響應 ---- 只要 action.type 不是惟一, 那麼就必然會出現這種狀況
這一點能夠被利用來作一些特定場景 , 但糟糕的設想是: 一個應用中有 未知數相同的 action.type, 在某一處的修改觸發了全部狀態的修改 ;
理想情況下 , 咱們應該只修改當前狀態的值 , 而不該擴寬它的影響範圍 , 所以稱它爲缺陷。 咱們在開發中應該儘可能對 action.type 命名惟一。
始終記住 redux提供可預測化的狀態管理。目前它並不完美 , 但足夠優秀。