前言
隨著 JavaScript 單頁(yè)應(yīng)用開(kāi)發(fā)日趨復(fù)雜,JavaScript 需要管理比任何時(shí)候都要多的 state (狀態(tài))。 這些 state 可能包括服務(wù)器響應(yīng)、緩存數(shù)據(jù)、本地生成尚未持久化到服務(wù)器的數(shù)據(jù),也包括 UI 狀態(tài),如激活的路由,被選中的標(biāo)簽,是否顯示加載動(dòng)效或者分頁(yè)器等等。
管理不斷變化的 state 非常困難,因此,如何優(yōu)雅的管理應(yīng)用中的數(shù)據(jù)狀態(tài)成為了一個(gè)需要解決的問(wèn)題。
當(dāng)下已有不少優(yōu)秀的狀態(tài)管理工具可以幫助我們解決這一難題,接下來(lái)的這段時(shí)間,我會(huì)選擇現(xiàn)目前比較流行的 Redux 和 Mobx來(lái)進(jìn)行學(xué)習(xí)實(shí)踐,并將學(xué)習(xí)軌跡記錄于此,便于日后查閱和鞏固。
本篇文章記錄Redux的一些基礎(chǔ)知識(shí)。
Redux是什么
專注于狀態(tài)管理的庫(kù), 和 React 解耦。Redux 可以支持 React、Angular、Ember、jQuery 甚至純 JavaScript?;局行乃枷肟梢悦枋鋈缦拢?/p>
(state, action) => newState
Redux核心概念
- state-狀態(tài)樹(shù)
例如:
{
todos: [{
text: 'Eat food',
completed: true
}, {
text: 'Exercise',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}
- Action
Action本質(zhì)上是JavaScript普通對(duì)象,是把數(shù)據(jù)從應(yīng)用傳到 store 的有效載荷。我們約定,action 內(nèi)必須使用一個(gè)字符串類型的 type 字段來(lái)表示將要執(zhí)行的動(dòng)作。除了 type 字段外,action 對(duì)象的結(jié)構(gòu)完全由開(kāi)發(fā)者自己決定。
{
type: '吃蘋果',
text: '我吃了一個(gè)蘋果'
}
- Reducer
Reducer 就是一個(gè)純函數(shù),接收舊的 state 和 action,返回新的 state。其指定了應(yīng)用狀態(tài)的變化如何響應(yīng) actions 并發(fā)送到 store 的,記住 actions 只是描述了有事情發(fā)生了這一事實(shí),并沒(méi)有描述應(yīng)用如何更新 state。 - Store
Store 是把a(bǔ)ction 和 reducers聯(lián)系到一起的對(duì)象,有以下職責(zé):
(1)維持應(yīng)用的state;
(2)提供getState()方法獲取state;
(3)提供dispatch(action)方法更新state;
(4)通過(guò)subscribe(listener)注冊(cè)監(jiān)聽(tīng)器;
(5)通過(guò)subscribe(listener)返回的函數(shù)注銷監(jiān)聽(tīng)器;
簡(jiǎn)單的redux應(yīng)用
- 通過(guò)reducer新建store,隨時(shí)通過(guò)store.getState獲取狀態(tài)
- 需要狀態(tài)變更時(shí), 使用store.dispatch(action)來(lái)修改狀態(tài)
- Reducer 函數(shù) 接收state 和 action,返回新的state,可以用store.subscribe監(jiān)聽(tīng)每次修改
import { createStore } from 'redux'
// reducer,根據(jù)老的state和action, 返回新的state
const counter = (state={}, action) => {
switch (action.type) {
case '摘蘋果':
return state+1;
break;
case '吃蘋果':
return state-1;
break;
default:
return state;
break;
}
}
// 新建store
const store = createStore(counter)
// 獲取狀態(tài)
const init = store.getState()
console.log(`最初籃子里有${init}個(gè)蘋果`) // 最初籃子里有0個(gè)蘋果
const listener = () =>{
const current = store.getState()
console.log(`現(xiàn)在籃子里有${current}個(gè)蘋果`)
}
// 訂閱listener,每次修改state,都會(huì)執(zhí)行l(wèi)istener
const unsubscribe = store.subscribe(listener)
// 使用store.dispatch(action)來(lái)修改狀態(tài)
store.dispatch({ type: '摘蘋果'}) // 現(xiàn)在籃子里有1個(gè)蘋果
store.dispatch({ type: '摘蘋果'}) // 現(xiàn)在籃子里有2個(gè)蘋果
store.dispatch({ type: '吃蘋果'}) // 現(xiàn)在籃子里有1個(gè)蘋果
// 停止監(jiān)聽(tīng) state 更新
unsubscribe();
補(bǔ)充知識(shí)點(diǎn)
function counter(state=0, action) {...}
其中state=0是es6中為函數(shù)參數(shù)指定默認(rèn)值的寫法,即調(diào)用該函數(shù)時(shí),若不傳對(duì)應(yīng)的參數(shù),或傳undefined, 則使用指定的默認(rèn)值。
PS: 若有錯(cuò)誤或不準(zhǔn)確的地方,歡迎指正!感謝!