凡是用reactjs開(kāi)發(fā)的項(xiàng)目扒腕,但凡規(guī)模稍微大一些客年,都很可能要引入redux來(lái)管理組件狀態(tài)的變遷和組件彼此之間的通信投放,權(quán)威的解釋和說(shuō)明當(dāng)然是官方的這篇文章叮贩,但是几于,但是吃引,但是筹陵,這篇長(zhǎng)文處處透露著一種玄妙而不可言說(shuō)的味道,處處是一些principle镊尺,best practice朦佩,never,absolutely庐氮,you should……的字眼语稠,到處是強(qiáng)調(diào),加粗的段落旭愧,一些模糊的store颅筋,action,reducer之類(lèi)的抽象用詞输枯,我嘗試著寫(xiě)篇小文來(lái)記錄自己對(duì)Redux的學(xué)習(xí)理解過(guò)程议泵。
1. 從reactjs本身談起
正如官方文檔強(qiáng)調(diào)的,我們只做view層桃熄,是的先口,reactjs利用JSX把UI的開(kāi)發(fā)演進(jìn)到另一種模式,就個(gè)人觀點(diǎn)瞳收,我并不覺(jué)得其比其他基于模版的view技術(shù)究竟高到哪里去碉京,有人說(shuō)virtual dom技術(shù)比原來(lái)的直接操作dom來(lái)得效率高,拜托螟深,它只是節(jié)省了dom元素的尋找時(shí)間谐宙,react使得程序員從數(shù)據(jù)變化耦合ui變化的面條代碼中抽離出來(lái),每個(gè)組件保持了極高的內(nèi)聚性界弧,給使用者帶來(lái)了極大的方便凡蜻,使得在view層堆積木式的開(kāi)發(fā)成為可能,每個(gè)UI組件的state對(duì)于使用者是完全透明的垢箕,使用者只要為它設(shè)置好初始的props划栓,組件本身可以響應(yīng)各種事件來(lái)改變自身的狀態(tài),重新渲染外觀条获。如果每一個(gè)組件都不需要跟外界通信忠荞,都不需要跟別的組件聯(lián)動(dòng),那傳統(tǒng)的state,props便足以對(duì)付所有的開(kāi)發(fā)委煤。但是組件之間的通信堂油,這對(duì)一個(gè)稍微大型的SPA應(yīng)用來(lái)說(shuō),都是必須要有的功能素标。
2. 我們能從傳統(tǒng)的設(shè)計(jì)模式汲取什么
observer/observable称诗,Event Listener是我們最常用的手段來(lái)注冊(cè)萍悴,監(jiān)聽(tīng)头遭,響應(yīng)外界感興趣的變化,假設(shè)react組件A監(jiān)聽(tīng)了組件B的變化癣诱,當(dāng)組件B變化時(shí)它調(diào)用A注冊(cè)的回調(diào)函數(shù)计维,同時(shí)把自己的state傳遞給B,注意撕予,這里已經(jīng)完全破壞了組件的邊界鲫惶,當(dāng)A拿到B的state時(shí),它可以做任何修改实抡,所以實(shí)現(xiàn)時(shí)欠母,B應(yīng)該clone了一份自己最新的的state給A,那么問(wèn)題來(lái)了吆寨,
1. A組件必須理解B組件的實(shí)現(xiàn)細(xì)節(jié)赏淌,不然它沒(méi)辦法理解B的state的含義,但state本身是應(yīng)該對(duì)外界透明的啄清。
2. 每個(gè)UI組件都必須暴露注冊(cè)監(jiān)聽(tīng)的接口
3. 大量的state復(fù)制操作
我們想一想如何自己解決這些問(wèn)題六水,
1. ?想不到,是的辣卒,真的想不到啊
2. ?加個(gè)屬性掷贾,不好辦啊,A,C組件都想監(jiān)聽(tīng)B的變化怎么辦荣茫?
3. ?前兩個(gè)解決不了想帅,這個(gè)就不是個(gè)問(wèn)題啊
3. Redux 是怎么解決問(wèn)題的
1. ?計(jì)算機(jī)問(wèn)題總是可以通過(guò)分層來(lái)解決,Redux引入了一個(gè)稱(chēng)之為store的層啡莉,所有的組件不再維護(hù)自身的狀態(tài)港准,所有的狀態(tài)都在這一層來(lái)維護(hù),作為一個(gè)best practice票罐,Redux推薦用扁平的方式來(lái)為維護(hù)這個(gè)store叉趣,所以每個(gè)狀態(tài)都必須小心命名以防止同名沖突,一般的我都會(huì)加組件名作為前綴该押。
2. ?既然組件不再維護(hù)狀態(tài)的變化疗杉,那么組件的渲染必須通過(guò)組件屬性的變化來(lái)完成,所以Redux在原組件外面重新包了一層,然后外層通過(guò)更新內(nèi)層屬性來(lái)觸發(fā)內(nèi)層UI的重新渲染烟具,內(nèi)層組件所有的數(shù)據(jù)通過(guò)props來(lái)綁定梢什,同時(shí)調(diào)用通過(guò)屬性傳過(guò)來(lái)的回調(diào)函數(shù)來(lái)與外界通信,所以組件本身的內(nèi)聚性得到了保證朝聋,組件總是通過(guò)屬性來(lái)工作嗡午,需要特別指出的是,組件本身并不需要知道是否工作在Redux的上下文冀痕,它只是根據(jù)自身的業(yè)務(wù)邏輯來(lái)調(diào)函數(shù)荔睹,所以Redux本身也不需要必須和reactjs綁定,這個(gè)外部組件傳進(jìn)來(lái)的回調(diào)函數(shù)一般只會(huì)dispatch一個(gè)action言蛇,action本身只是一個(gè)必須包含type屬性的普通javascript對(duì)象僻他,所謂的reducer就是actionlistener,它根據(jù)action的type來(lái)更新全局的store腊尚,很顯然reducer針對(duì)同一個(gè)action會(huì)有多份實(shí)現(xiàn)吨拗,比如A,C組件對(duì)于B組件dispatch出來(lái)的同一個(gè)action有不同的反應(yīng)。
(未完待續(xù))