Redux is a predictable state container for JavaScript apps.
簡單的說就是Redux能夠管理js app的狀態(tài),狀態(tài)是由數(shù)據(jù)維護的,也就是說Redux是管理數(shù)據(jù)的。那么Redux是怎么管理數(shù)據(jù)的呢?
store
一個Redux app中只有一個store,所有的數(shù)據(jù)都在這個store中,而通過createStore(reducer, [initState])
,initState是可選參數(shù),也就是說決定store的是reducer,reducer決定store中存放什么樣的數(shù)據(jù)、處理什么樣的數(shù)據(jù)、處理數(shù)據(jù)的方式。
store在創(chuàng)建的時候內(nèi)部會執(zhí)行dispatch({ type: ActionTypes.INIT })
,用來初始化整個store的數(shù)據(jù)結(jié)構(gòu),同時獲取reducer中的默認數(shù)據(jù)。之所以能拿到全部的數(shù)據(jù)結(jié)構(gòu),是因為在dispatch({ type: ActionTypes.INIT })
的時候,所有的reducer都會執(zhí)行,并根據(jù)reducer的combine結(jié)構(gòu)生成數(shù)據(jù)。在Redux內(nèi),每執(zhí)行一次dispatch,所有的reducer都會執(zhí)行。
reducer
所以這里就有個問題,如果reducer比較多的時候,性能是不是就會出問題。大家可能會想到減少reducer,這也是一個辦法,但是如果刻意減少reducer的話,可能會導(dǎo)致某個reducer內(nèi)過于復(fù)雜,后期難以維護。
const dispatcher = (state={}, action) {
switch (action.type) {
case "TYPE1":
case "TYPE2":
return reducerFirst(state, action)
case "TYPE3":
return reducerSecond(state, action)
default:
return state
}
}
通過這樣簡單的過濾就可以實現(xiàn)只讓對action感興趣的reducer執(zhí)行,簡單,方便,快捷。
action
action是個object,它必須有個type屬性,一般是個常量,來標示action類型,方便reducer處理。除去type剩下的一般就是要處理的數(shù)據(jù),如果數(shù)據(jù)比較簡單可以直接使用Object.assign({}, state, action.data)
來處理,這種方法僅適合簡單數(shù)據(jù)。
如果是復(fù)雜數(shù)據(jù),有較深的層級,就要使用深度拷貝,這時候你可以使用lodash的cloneDeep進行深度拷貝。
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// ? false
immutable
但是復(fù)雜數(shù)據(jù)的深度拷貝是很花性能的,這個時候就可以使用immutable.js來解決這個問題。immutable不可改變的意思,在Object-C中是原生提供這種數(shù)據(jù)類型的。對immutable.js生成的數(shù)據(jù)進行操作之后總是返回一個新的數(shù)據(jù),原有的數(shù)據(jù)不會改變。
var Immutable = require('immutable');
var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 50);
map1.get('b'); // 2
map2.get('b'); // 50
immutable.js通過結(jié)構(gòu)共享來解決的數(shù)據(jù)拷貝時的性能問題,數(shù)據(jù)被set的時候,immutable.js會只clone它的父級別以上的部分,其他保持不變,這樣大家可以共享同樣的部分,可以大大提高性能。如圖
subscribe
每次執(zhí)行dispatch,通過subscribe注冊的listener都會被執(zhí)行,如果listener較多,或者listener內(nèi)部處理比較復(fù)雜也會對性能產(chǎn)生影響, 而且在listener內(nèi)部很難區(qū)分哪個數(shù)據(jù)被改變了,如果在listener內(nèi)部繼續(xù)dispatch,而沒有處理好執(zhí)行dispatch條件的話,很容易造成dispatch->listener->dispatch死循環(huán)。所以建議通過middleware的方式來處理,而且在middleware內(nèi)部可以知道action是什么,就可以只處理關(guān)心的action。
總結(jié)
預(yù)分配reducer、精簡reducer
精簡action數(shù)據(jù)或使用immutable.js
使用middleware處理特殊需求(reducer中不方便處理的需求)