對於沒有使用過redux的同窗,一來直接打開官網開始擼教程恐怕大多都對裏面提到的各類概念一臉懵,而打開論壇上的各類野生教程又會發現,或許是由於redux的源碼大概只有三百多行,所以論壇上寫的比較優秀的教程都深刻到redux的源碼中,須要你花時間理清redux的原理以後你才知道這東西要怎麼用。所以我嘗試在此寫一篇懶人教程,但願能經過比較通俗易懂的語言,以類比的方式向沒有接觸過redux的朋友解釋一下它是幹嗎用的,具體要怎麼用。java
下面開始個人表演。react
做爲開發者,咱們在選擇工具和庫時,切忌"爲了用而用",而應該清楚咱們要用的工具是用來解決什麼問題的,在咱們的開發場景中是否會碰到這樣的問題,用了這個工具後能不能幫咱們解決問題。搞清楚這些再去學習對應的工具和庫,工具才能稱之爲工具,不然就變成了工具是開發者的主人了。所以,在學習redux以前,首先應該瞭解一下爲何須要redux。 說起redux的時候,經常跟react聯繫在一塊兒,可是其實redux並不是是爲react定製的,首先要明確,redux只是一個架構模式,它要解決的是全局狀態很差管理這個問題,你能夠在任何有這樣的問題的場景下使用它。咱們來看這樣一個例子:redux
function showName(name) {
console.log("user's name: ", name);
}
function showAge(age) {
console.log("user's age: ", age);
}
window.user = {
name: 'Bob',
detail: {
age: 11,
gender: 'male'
}
}
/* ......不少不少模塊 */
showName(user.name);
showAge(user.detail.age);
複製代碼
假設有這樣一個變量user,它存儲了一個用戶的我的信息,這個信息可能在代碼的不少模塊中被讀寫,爲了方便, 咱們把這個變量設置爲全局變量。然而如今問題來了,這個user是一個在裸奔的變量,任何模塊均可以輕易地修改它,假如我指望在showName的時候打印Bob,可是實際上卻打印了undefined,那麼在這"不少不少個模塊中",到底是誰修改了user變量,你根本無法定位,其實這也是老生常談的儘可能避免全局變量的緣由。然而矛盾在於,雖然我知道定義全局變量可能會帶來混亂,可是有些變量確實須要被各類不一樣的模塊使用,我不得不把它定義成全局變量,在大型應用中,這樣的全局變量可能還很多,並且數據結構還可能很是複雜。所以,在這樣的場景下,咱們迫切須要一個數據的管理者制定好全局變量使用規範,幫咱們管理全局變量——而這就是redux作的事情。api
俗話說的好,在計算機領域,若是有什麼問題是加一層中間層解決不了的,那就加兩層。而redux就是這個中間層,再來回顧一下咱們面臨的痛點:一個須要被全局共享的很是重要的變量(下文稱之爲狀態),卻能夠被散落的模塊肆意妄爲地修改: 數組
首先,亂世用重典,咱們須要先頒佈一個《redux共和國狀態管理條例》,之後你們誰要修改狀態,都得寫社會主義法治程序,按照條例規定好的操做來修改狀態。在這部《條例》的開頭,先昭告天下咱們要管理的狀態(state)的初始值是什麼,而後,咱們一條一條地列舉針對這個狀態,你能夠進行哪些操做(action.type), 以及這個操做對狀態的修改是什麼。好比如今咱們須要管理一個數組,它的初始值是一個空數組,咱們規定對這個數組的合法操做有添加一個項,刪除一個項和清空整個數組,按照剛纔的思路,咱們用代碼頒佈一個《數組狀態管理條例》:bash
const initState = [];
const reducer = (state = initState, action) => {
switch(action.type) {
case 'add':
return [...state, action.addedItem];
case 'delete':
return [...state.slice(0, action.deletedIndex), ...state.slice(action.deletedIndex + 1)];
case 'clear':
return []
default:
return state;
}
}
複製代碼
好了,無需多言了吧,如今你已經知道redux中最重要的兩個概念reducer和action是什麼了,reducer正是咱們剛纔說的《redux共和國狀態管理條例》,而action則是條例裏的細則。不過或許你已經發現,雖然咱們說在條例的細則中定義好了如何去修改狀態, 可是,咱們並無真正地去"修改"狀態。聽起來彷佛有點繞,拿add這個操做爲例,咱們並無用數據結構
...
switch(action.type) {
case 'add':
state.push(action.addedItem);
return state;
...
}
複製代碼
這種寫法,而是架構
...
switch(action.type) {
case 'add':
return [...state, action.addedItem];
...
}
複製代碼
把原數組拷貝了一遍,生成了一個新數組,而後在新數組的末尾添加了一個新的項,最後再把這個新的數組返回做爲狀態的最新值,也就是說,咱們不是直接去修改狀態,而是根據舊狀態,返回一個新狀態。實際上,按照這種寫法,咱們寫出的reducer就是一個純函數,所謂純函數須要知足兩個條件:app
關於reducer爲何要寫成純函數,我以爲這是一個不得不結合redux源碼單獨寫一篇文章分析的問題,可是既然都說是懶人教程,只但願你會用,至於原理能夠後面又深究,如今你能夠暫且把它當作霸道總裁redux的一個奇怪的小癖好。異步
好了,咱們已經有《redux共和國狀態管理條例》了,如今還缺一個條例的堅決執行者。因而咱們用createStore函數,傳入咱們制定好的法律——reducer,它將返回一個執行法律的檢察官——store。如今,對狀態的讀寫都得通過store之手,要讀取狀態值,就調用store.getState()
; 要修改狀態,就得先學習一下法律知識,看看reducer中有哪些合法的action,而後調用store.dispatch(action)
對狀態進行修改; 同時, 你也能夠訂閱狀態的改變,給store.subscribe
傳入一個回調函數,每一次狀態改變時,都會執行一次這個回調函數——這是一個典型的觀察者模式。
如今來看下面這段代碼,能看懂的話說明你已經掌握redux的核心用法了, 看不懂的話能夠再把剛纔這個治亂世的過程再品一品
import { createStore } from 'redux';
const initState = [];
const reducer = (state = initState, action) => {
switch(action.type) {
case 'add':
return [...state, action.addedItem];
case 'delete':
return [...state.slice(0, action.deletedIndex), ...state.slice(action.deletedIndex + 1)];
case 'clear':
return []
default:
return state;
}
};
const store = createStore(reducer);
// 訂閱狀態變化
store.subscribe(() => {
console.log(store.getState());
})
// 添加一個項
store.dispatch({
type: 'add',
addedItem: 1
});
// 又添加一個項
store.dispatch({
type: 'add',
addedItem: 2
});
刪除一個項
// store.dispatch({
type: 'delete',
deletedIndex: 0
});
// 清空狀態
store.dispatch({
type: 'clear'
})
複製代碼
或許你已經發現,使用redux一點都不難,其核心思想無非就是制定規則(reducer)和遵照規則(store.dispatch)罷了。 在這個基礎上,redux總裁還想再完善一下本身制定的這套機制,以應對更加複雜的狀況。試想一下,若是這個redux共和國只有30個國民,可能尚未你高中的班級人多,那麼頒佈一部像大家班班規同樣規模的《管理條例》就綽綽有餘了,可是若是這個redux共和國像我泱泱華夏同樣地大物博,你就得分別頒佈《redux共和國刑法》,《redux共和國婚姻法》,《redux共和國未成年人保護法》.......最終這些法律才完整組成共和國的法律體系。回到程序世界,reudx提供了combineReducer這個api,容許你在管理大型應用的狀態時,分別寫一些小粒度的reducer,而後用這個api把它們組合成一個總reducer以後又傳給createStore。
另外,不一樣國家檢察官執法時候的花式姿式都不太同樣,例如美國警察抓犯人的時候都喜歡先說一句「你有權保持沉默,可是你說的每一句話都將成爲呈堂證供」。或許你也但願在每一次store.dispatch時能在控制檯打印一句「xxx狀態你有權保持沉默,可是你的值如今將從xxx被改變爲xxx」,那麼你能夠把這個例行程序經過插件機制在createStore的時候告訴你的檢察官,只須要使用redux提供的applyMiddleware這個api就行。社區裏已經提供了各類這樣的執法前的花式姿式插件,好比redux-thunk用於方便處理異步狀態變動,redux-logger用於在狀態變動時打印日誌等。
最後,把redux的使用方式用下面這張圖總結一下
很好,如今咱們已經搞清楚如何用redux來把混亂的全局變量管理得層次分明的了,休息一下,或者直接進入下一篇文章 《react-redux懶人教程》咱們就來看看這個霸道總裁是怎麼管理你的react帝國的。