Immutable.js在react + router + redux項目中的應(yīng)用
先介紹一下Immutable:
Immutable.js的出現(xiàn)源于Functional Programming的思想,即所有數(shù)據(jù)應(yīng)該是復(fù)制過來,而不是直接修改。相關(guān)介紹看它官網(wǎng):
https://facebook.github.io/immutable-js/
所以如果你有一些編程經(jīng)驗,可以理解為Immutable就是另外一個數(shù)據(jù)結(jié)構(gòu)的庫。就好像從ArrayList換成LinkedList一樣。在Immutable.js下,就是從JavaScript語法自有的Array(就是[])和Object({ }),換到Immutable.List和Immutable.Map了。
但是ArrayList和LinkedList畢竟都繼承于List,接口上比較一致,換起來問題不大,但是想用Immutable換JavaScript原生,就要略復(fù)雜些。
var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 50);
map1.get('b'); // 2
/* ----------------悠長悠長的分割線---------------- */
var list1 = Immutable.List.of(1, 2);
var list2 = list1.push(3, 4, 5);
var list3 = list2.unshift(0);
var list4 = list1.concat(list2, list3);
復(fù)雜歸復(fù)雜,不過是多注意一點吧。
然后要說到redux和router
Redux有一個combineReducers方法,可以做到Reducer的拆分。比如:
combineReducers({
user: userReducer,
dashboard: dashboardReducer,
})
那么問題來了:
當(dāng)你獲取state的時候,你是用state.get('user')還是用state.user?
顯然要用state.user。因為combineReducers不認(rèn)識Immutable啊。
(不要告訴我混用,一層結(jié)構(gòu)可以這樣,多層呢?多人合作呢?一處蒙逼,處處報錯?。?/p>
所以如果你想在一個react + router + redux的項目下用Immutable,要么就局部使用(局部的話,基本會很nightmare吧),要么就換全套的。
然后就是看這里(這哥們把combineReducers給重新寫了):
https://github.com/gajus/redux-immutable
用他們家的combineReducers,你就可以放心地用state.get('user')。
在解決combineReducers的同時,他們家還順帶解決了react-router-redux的問題(試想router作為state下的routing模塊卻不懂用Immutable該多呵呵):
https://github.com/gajus/redux-immutable#using-with-react-router-redux
說了這么多,怎么用呢
首先你的項目是react + router + redux的標(biāo)配。
然后你要引入Immutable。
那么你該這樣:
- 引入redux-immutable
- 按照redux-immutable的README.md把history什么的配置好(Ctrl+C, Ctrl+V)
- 所有reducer合并的時候換用redux-immutable的
combineReducers - 所有數(shù)據(jù)出入state用Immutable.js的
Immutable.List和Immutable.Map(這個才是正題)
還有什么要注意的嗎?
組件的問題:
從redux過來的思想是把組件分成Smart和Dumb。Smart組件負(fù)責(zé)把數(shù)據(jù)接進來,Dumb組件負(fù)責(zé)使用數(shù)據(jù),并只關(guān)注props。所以Immutable要覆蓋Smart和Dumb嗎?
我個人觀點是這樣的:
Dumb組件基本都是要抽象出來給多個項目共用的。這部分組件不支持Immutable應(yīng)該更好些,否則就被綁死在Immutable上了。
那這么說,Dumb里的數(shù)據(jù)是JavaScript原生的,豈不是享受不到Immutable帶來的好處?
數(shù)據(jù)已經(jīng)復(fù)制給了組件,為了兼容性犧牲一點這個也沒啥吧?
這個想法背后的結(jié)論就是:
redux概念里的Container在做state與props之間,props與dispatch之間的對接的時候,也同時做了Immutable與原生的相互轉(zhuǎn)換。(Adapter Pattern吧)
測試的時候:
你會想console.log一下當(dāng)前的數(shù)據(jù)吧,把Immutable.List打出來看著很累的,建議用console.log(imtb.toJS())
可是debug的時候呢?
題外話
如果這些特性是JavaScript本身內(nèi)置的就好了。