Redux是一個程序架構,源於Flux(Facebook提出的一種架構),然而,它不只能夠應用於React,還能夠應用於其餘任何框架中。值得一提的是,Redux的源代碼不多,可是他的邏輯拆分和函數式編程的設計思想是很是值得學習的。javascript
當一個JavaScript單頁應用變得愈來愈複雜時,咱們要處理的數據(model)也變得愈來愈龐大,隨之而來的是每一個數據的狀態(state)會變得難以維護。當一個model改變時,咱們可能要手動處理由此引起的其餘model的變化,更糟糕的是,其餘model變化可能又會引發另外一些model的變化,這樣產生連鎖反應。最後咱們很容易就會不記得model在何時以及如何發生改變。這正是Redux能夠解決的最大痛點之一—以統一的方式管理數據狀態。html
統一的數據狀態管理體現爲如下2個方面:java
Action 是把數據從應用傳到 store 的有效載荷。它是 store 數據的惟一來源。直白的說,action就是一種消息類型,他告訴Redux是時候該作什麼了,並帶着相應的數據傳到Redux內部(即接下來介紹的Reducer)。
Action就是一個簡單的對象,其中必需要有一個type屬性,用來標誌動做類型(reducer以此判斷要執行的邏輯),其餘屬性用戶能夠自定義,但要儘可能簡單。如:
{type: SET_ALL,index: 5}
react
Action Creator是一個用來自動生成Action的函數,這也是Redux函數式編程的一種體現。一般,咱們會按照業務邏輯或組件把相關的Action Creator放在一個文件中,形式以下:編程
export const SHOW_SLIDER = 'SHOW_SLIDER';
export const RIGHT_SLIDER = 'RIGHT_SLIDER';
export const showSliderAction = (index) => {
return {
type: SHOW_SLIDER,
index
};
}
export const rightSliderAction = (length) => {
return {
type: RIGHT_SLIDER,
length
};
}
複製代碼
其中showSliderAction和rightSliderAction就是Action Creator。
因爲Action Creator的形式大致相同,咱們還能夠建立一個用來生成Action Creator的函數以進一步簡化。redux
export const makeCreateAction = (type, ...keys) => {
return (...data) => {
let action = {type};
keys.forEach((v,i) => action[v] = data[i]);
return action;
}
}
export const showSliderAction = makeCreateAction(SHOW_SLIDER, index);
export const rightSliderAction = makeCreateAction(RIGHT_SLIDER, length);
複製代碼
Reducer 指定了應用狀態的變化如何響應 actions 併發送到 store 的,action只是告訴Redux該幹什麼了,並無告訴他怎麼幹,而reducer就是根據action處理state如何改變的邏輯。
Reducer必須是一個純函數(緣由稍後解釋),他根據action處理state的更新,若是沒有更新或遇到未知action,則返回舊state;不然返回一個新state對象。注意:不能修改舊state,必須先拷貝一份state,再進行修改,也可使用Object.assign函數生成新的state。另外,state參數需先進行初始化。實例代碼以下:bash
//初始狀態
let initialState = {hiddenClass: 'g-hidden',currentIndex:0};
let sliderReducer = function (state = initialState, action) {
switch(action.type){
case sliderAction.SHOW_SLIDER:
return {hiddenClass: '',currentIndex:action.index};
case sliderAction.RIGHT_SLIDER:
if(state.currentIndex == action.length-1){
return Object.assign({}, state, {currentIndex:0});
}else{
return Object.assign({}, state, {currentIndex:Number.parseInt(state.currentIndex)+1});
}
default:
return state;
}
}
export default sliderReducer;
複製代碼
使用純函數的緣由:
首先,純函數的特色是:架構
若是不使用純函數,即直接更改state值會怎麼樣呢?併發
… …
case sliderAction.RIGHT_SLIDER:
if(state.currentIndex == action.length-1){
state.currentIndex = 0;
return state;
}
… …
複製代碼
以後會發現,不管state如何變化,UI都不會更新。如下是Redux的部分源碼:框架
import { combineReducers } from 'redux';
import photomainReducer from './photomainReducer';
import sortReducer from './sortReducer';
import sliderReducer from './photoSliderReducer';
export default combineReducers({
photomainReducer,
sortReducer,
sliderReducer
});
複製代碼
1.維持應用的 state;
2.提供 getState() 方法獲取 state;
3.提供 dispatch(action) 方法更新 state;
4.經過 subscribe(listener) 註冊監聽器;
5.經過 subscribe(listener) 返回的函數註銷監聽器。
const store = createStore(
indexPhotomainReducer,
);
export default store;
複製代碼
// 每次 state 更新時,打印日誌
// 注意 subscribe() 返回一個函數用來註銷監聽器
const unsubscribe = store.subscribe(() =>
console.log(store.getState())
)
// 中止監聽 state 更新
unsubscribe();
複製代碼
store.dispatch(SHOW_SLIDER)
複製代碼
let initialState = {hiddenClass: 'g-hidden',currentIndex:0};
let sliderReducer = function (state = initialState, action) {
switch(action.type){
case sliderAction.SHOW_SLIDER:
return {hiddenClass: '',currentIndex:action.index};
default:
return state;
}
}
複製代碼
store.subscribe(listener);
複製代碼
function listerner() {
let newState = store.getState();
component.setState(newState);
}
複製代碼
以上爲Redux的數據流動過程。
本篇到此告一段落,下一篇介紹Redux的異步實現。