2017.9.10日 教師節
1. redux的基本原理
redux就是對一個倉庫(store)的操作,我們可以布置好多倉位(state)(如: 水果、零食、糕點)等,他們每一個倉位(state)存儲着不同的物品,每一個倉位都有一個操作系統(reducer), 這個操作系統可以進行入庫物品(ADD)、統計件數(COUNT)、篩選好(FILTER_GOOD)/壞(FILTER_BAD)等操作,這些操作都用一個統一的標簽(type)來表示。好了比喻就到這里。
redux規定:
1. 用戶每一次操作store都要觸發一個action,這個action僅僅是告訴redux:1. 我要操作的類型type,2. 我提供的數據。觸發條件dispatch({type: ... , data: ...});
function addTodo(content) { return { type: ADD_TODO, content: content } } dispatch(addTodo('你好啊'))
如上代碼,我們觸發了一個行為ADD_TODO
2. 觸發一個行為后,真正的state操作在reducer里完成,reducer里要做的事: 1. 任何情況都要返回一個state,2. 根據不同的type做不同的操作
function todoApp(state=[], action) { switch(action.type) { case ADD_TODO: return [ ...state, { content: action.content, completed: false } ], case REMOVE_TODO: return [ ...state.filter(item => item.id != action.id) ] default: return state } }
差不多就像上面這樣,定義了一個reducer函數,這個函數為兩個行為做state處理,ADD_TODO、REMOVE_TODO。 該reducer函數接收兩個參數,一個state是當前reducer對應的state,action是dispatch傳遞過來的行為對象。這個函數一定會返回一個新的state。差不多這個意思,不知道代碼寫錯了沒。
2. redux源碼解析(看着源碼看本節)
兩個核心方法: combineReducers、createStore
4.1 Reducers 合並函數 combineReducers
用途: 將多個reducer合並成一個。
源碼:
1. 該函數接收一個參數reducers,reducers代表着要合並的所有reducer的鍵值對。
2. redux獲取reducers所有鍵並遍歷,過濾出鍵對應的值是function的項目,生成了最終的reducers對象finalReducers,以防非法reducer值入侵。
3. redux遍歷finalReducers對象並檢查,是否每一個函數每一次執行總會返回一個state,並做標記shapeAssertionError。
4. 檢查完畢后,回一個閉包函數。該閉包函數就是總的reducer函數combination。
在未來的某個時間,這個combination函數會被執行:
1. 如果shapeAssertionError是真,意味着有錯誤,不執行邏輯。
2. 遍歷finalReducers,拿到每個key值和reducers函數, 根據key值從state中拿到當前reducer下的當前狀態previousStateForKey, 執行reducer函數並把previousStateForKey和action傳入, 執行結果必定返回一個nextStateForKey,記住這個state。
3. 經過一次遍歷后,每一個reducer函數都執行並返回了新的state。如果新的state和原來的state一致,返回原來的state,如果不一致,返回新的state。
4.2Store 創建函數createStore
用途: 創建store和工具方法
1. 該函數接收三個參數(只說前兩個): reducer(總的reducer函數,combineReducers函數生成的combination函數), preloadedState(自定義的初始化state)
2. 將reducer函數保存在currentReducer變量,初始化一個currentState為preloadedState或者undefined,后續redux會根據currentState值用reducer函數來初始化state。
3.初始化currentListeners、nextListeners為空數組,這兩個數組為觀察者模式服務,存儲監聽函數。
4.定義一個subscribe函數用來訂閱一個監聽函數,同時返回一個閉包函數unsubscribe,當執行這個unsubscribe函數時,當前監聽函數移除監聽隊列。
5.定義dispatch函數,最核心的函數,其工作非常簡單,執行當前的reducer函數currentReducer,並把當前currentState和action傳遞過去。通過currentReducer函數我們可以獲取到用戶需要下一步得到的state,存儲在currentState中為視圖層所用。如果有監聽函數,就遍歷並執行他們。
6.getState函數返回當前state狀態樹。
3. 注意事項
1. 每一次dispatch都會遍歷所有的reducer, 每一個reducer可以對同一行為做不同處理。dispatch要做什么事,只看type值!
2.每一個reducer函數必須有對state為undefined時的處理,因為redux創建store時會初始化一次store,此時store中還沒有任何值。
3. reducer函數是個純函數,只做數據的改變,不做請求、定時器之類的邏輯。
4. 一個store就是一個state的樹狀結構,你只能通過reducer來改變他的數據。