Immutable.js在react + router + redux項(xiàng)目中的應(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)驗(yàn),可以理解為Immutable就是另外一個(gè)數(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ù)雜咙鞍,不過是多注意一點(diǎn)吧。
然后要說到redux和router
Redux有一個(gè)combineReducers
方法趾徽,可以做到Reducer的拆分续滋。比如:
combineReducers({
user: userReducer,
dashboard: dashboardReducer,
})
那么問題來了:
當(dāng)你獲取state的時(shí)候,你是用state.get('user')
還是用state.user
孵奶?
顯然要用state.user
吃粒。因?yàn)?code>combineReducers不認(rèn)識(shí)Immutable啊。
(不要告訴我混用拒课,一層結(jié)構(gòu)可以這樣徐勃,多層呢?多人合作呢早像?一處蒙逼僻肖,處處報(bào)錯(cuò)啊)
所以如果你想在一個(gè)react + router + redux的項(xiàng)目下用Immutable卢鹦,要么就局部使用(局部的話臀脏,基本會(huì)很nightmare吧)劝堪,要么就換全套的。
然后就是看這里(這哥們把combineReducers給重新寫了):
https://github.com/gajus/redux-immutable
用他們家的combineReducers揉稚,你就可以放心地用state.get('user')
秒啦。
在解決combineReducers
的同時(shí)搀玖,他們家還順帶解決了react-router-redux的問題(試想router作為state下的routing模塊卻不懂用Immutable該多呵呵):
https://github.com/gajus/redux-immutable#using-with-react-router-redux
說了這么多余境,怎么用呢
首先你的項(xiàng)目是react + router + redux的標(biāo)配。
然后你要引入Immutable灌诅。
那么你該這樣:
- 引入redux-immutable
- 按照redux-immutable的README.md把history什么的配置好(Ctrl+C, Ctrl+V)
- 所有reducer合并的時(shí)候換用redux-immutable的
combineReducers
- 所有數(shù)據(jù)出入state用Immutable.js的
Immutable.List
和Immutable.Map
(這個(gè)才是正題)
還有什么要注意的嗎芳来?
組件的問題:
從redux過來的思想是把組件分成Smart和Dumb。Smart組件負(fù)責(zé)把數(shù)據(jù)接進(jìn)來猜拾,Dumb組件負(fù)責(zé)使用數(shù)據(jù)即舌,并只關(guān)注props。所以Immutable要覆蓋Smart和Dumb嗎挎袜?
我個(gè)人觀點(diǎn)是這樣的:
Dumb組件基本都是要抽象出來給多個(gè)項(xiàng)目共用的顽聂。這部分組件不支持Immutable應(yīng)該更好些,否則就被綁死在Immutable上了盯仪。
那這么說紊搪,Dumb里的數(shù)據(jù)是JavaScript原生的,豈不是享受不到Immutable帶來的好處磨总?
數(shù)據(jù)已經(jīng)復(fù)制給了組件嗦明,為了兼容性犧牲一點(diǎn)這個(gè)也沒啥吧笼沥?
這個(gè)想法背后的結(jié)論就是:
redux概念里的Container在做state與props之間蚪燕,props與dispatch之間的對(duì)接的時(shí)候,也同時(shí)做了Immutable與原生的相互轉(zhuǎn)換奔浅。(Adapter Pattern吧)
測試的時(shí)候:
你會(huì)想console.log
一下當(dāng)前的數(shù)據(jù)吧馆纳,把Immutable.List打出來看著很累的,建議用console.log(imtb.toJS())
可是debug的時(shí)候呢汹桦?
題外話
如果這些特性是JavaScript本身內(nèi)置的就好了鲁驶。