摘要:相關(guān)狀態(tài)父組件傳遞給子組件的狀態(tài)。外部狀態(tài)狀態(tài)是可以從視圖庫中移出來的,然后可以使用提供者消費(fèi)者模式把狀態(tài)重新連接回視圖庫。重新設(shè)計在我看來,重寫是有其必要性的,至少有以下個方面可以改進(jìn)得更友好。
Redux 學(xué)習(xí)起來很困難?寫起代碼來很啰嗦?
一起來看看 Rematch 的作者對 Redux 的思考和簡化吧~
原文:《Redesigning Redux》, Shawn McKay
都過了這么多年了,狀態(tài)管理的問題難道不應(yīng)該早就被解決了么?
個人直覺,開發(fā)者似乎都承認(rèn)一個潛規(guī)則,那就是狀態(tài)管理問題似乎比想象的更復(fù)雜。在本文,我們將一起探討你可能已經(jīng)遇到的問題:
我們真的需要一個狀態(tài)管理庫么?
Redux 的流行是否實(shí)至名歸?為什么?
我們是否能夠提出更好的狀態(tài)管理方案?如果是,怎么做?
真的需要狀態(tài)管理庫?前端開發(fā)并不僅僅是左右移動像素點(diǎn)。開發(fā)的真正藝術(shù)是掌握如何管理狀態(tài)。
簡單粗暴的答案是:狀態(tài)管理是復(fù)雜的,但是并非那么復(fù)雜。
以基于組件的視圖框架/庫為例,比如 React,讓我們來看看我們有哪些選擇:
1. 組件狀態(tài)存在于單個組件內(nèi)部的狀態(tài)。在 React 中,就是指使用 setState 來更新的 state。
2. 相關(guān)狀態(tài)父組件傳遞給子組件的狀態(tài)。在 React 中,就是指通過屬性傳遞給子組件的 props。
3. 供給狀態(tài)保存在根提供者中、通過組件樹傳遞給消費(fèi)者的狀態(tài)。在 React 中,對應(yīng)于 context API。
大多數(shù)的狀態(tài)都是存在于視圖中的,因?yàn)樗怯脕矸从秤脩艚缑娴摹D敲?,對于反映底層?shù)據(jù)和邏輯的其它狀態(tài),又屬于誰呢?
如果把所有的狀態(tài)都填塞到視圖中,那么就嚴(yán)重違背了關(guān)注點(diǎn)分離原則。它會把你牢牢地綁在一個 JS 視圖庫中,使得代碼難以測試。更有甚者,可能會為你帶來大麻煩,因?yàn)槟惚仨毘掷m(xù)不斷的思考和調(diào)整狀態(tài)的存儲之處。
由于架構(gòu)設(shè)計的改變,狀態(tài)管理會隨之變得復(fù)雜,并且通常很難判斷哪些組件需要哪些狀態(tài)。最簡單的做法是,在根組件上包含所有狀態(tài)。如果真要這么做的話,那么選用下一種方式會更好。
4. 外部狀態(tài)狀態(tài)是可以從視圖庫中移出來的,然后可以使用提供者/消費(fèi)者模式把狀態(tài)重新連接回視圖庫。
Redux 也許是最流行的狀態(tài)管理庫。它在過去的 2 年時間里取得了巨大的流行度。那么,為什么一個簡單的庫會獲得如此之多的關(guān)注呢?
是因?yàn)樗男阅芨呙??其?shí)并不是。實(shí)際上,它反而讓每一個必須處理的回調(diào)變得更慢了些。
那是因?yàn)樗唵??也決定不是。
論簡單的話,那么純 JS 才是。正如 TJ 所說:
那為什么大家不直接使用 global.state = {} 呢?
為什么使用 Redux本質(zhì)上,Redux 跟 TJ 所說的是同一件事,只不過 Redux 封裝了一些管道工具而已。
在 Redux 中,我們不能直接修改狀態(tài)。修改狀態(tài)的唯一方式是分發(fā)(Dispatch)一個動作(Action)到管道中,管道會自動根據(jù)動作去更新狀態(tài)。
從上圖可以看到,管道的中有 2 個監(jiān)聽器集合:中間件(Middleware)和訂閱(Subscription)。中間件一些是監(jiān)聽動作的函數(shù),用來處理類似日志記錄、開發(fā)工具和發(fā)起服務(wù)請求等功能。訂閱則是一些用來廣播狀態(tài)變更的函數(shù)。
最后,合成器(Reducer)函數(shù)負(fù)責(zé)把狀態(tài)變更拆分成更小、更模塊化、更容易管理的代碼塊。
和使用一個全局對象相比,Redux 確實(shí)簡化了開發(fā)過程。
綜上,我們可以把 Redux 看成是一個全局對象,該對象不僅提供了狀態(tài)更新前/后鉤子,而且能夠以簡單的方式合成新狀態(tài)。
不覺得 Redux 過于復(fù)雜么?的確過于復(fù)雜。在平時的開發(fā)過程中,有一些不可否認(rèn)的跡象,可以用來判斷框架 API 是否需要改進(jìn)。這些跡象可以歸納為下面這個公式:
其中,節(jié)省的時間是指使用該框架來開發(fā)所消耗的時間,學(xué)習(xí)的時間則是閱讀框架文檔、學(xué)習(xí)教程和掌握新概念的總時間。
Redux 本身是個精簡的庫,但是其學(xué)習(xí)曲線卻很陡峭。雖然有不少開發(fā)者能夠克服深入學(xué)習(xí)函數(shù)式編程的困難并從 Redux 獲益良多,但是也有很多開發(fā)者望而卻步,寧愿重新使用 jQuery。
在 jQuery 中,你并不需要理解什么是 “comonad”,也沒必要理解通過函數(shù)組合來管理狀態(tài)。
任何框架或者庫的目的都應(yīng)該是把復(fù)雜的事物抽象得更加簡單。
當(dāng)然我這么說并不是想指責(zé) Redux 的作者 Dan Abramov 。Redux 在其剛誕生初期就已經(jīng)變得非常流行,沒有足夠的時間來精雕細(xì)琢。
我們怎么能隨便重構(gòu)一個已經(jīng)被成千上萬開發(fā)者使用的庫呢?
我們又怎么能合理發(fā)布會影響到不計其數(shù)項(xiàng)目的重大變更呢?
沒人可以。但是我們可以提供更好的支持,比如完善文檔、推廣視頻教程和擴(kuò)大社區(qū)等。在這些方面,Dan Abramov 確實(shí)做得很棒。
又或者,還有另一種方式可以改變現(xiàn)狀。
重新設(shè)計 Redux在我看來,重寫 Redux 是有其必要性的,至少有以下 6 個方面可以改進(jìn)得更友好。
1. 初始化過程讓我們來看看一個基本的 Redux 初始化過程,如下圖左邊所示:
很多開發(fā)者走到這里一步就開始止步了,簡直是一看三不知。什么是 chunk ?compose 又是什么鬼?一個函數(shù)還能這么使用?
如果 Redux 是基于配置而不是函數(shù)組合的話,那么像右邊那樣的初始化過程明顯看起來更加合理。
2. 簡化狀態(tài)合成器Redux 中的狀態(tài)合成器能夠使用一個 switch 來代替多個不必要的 switch 。
假如狀態(tài)合成器是根據(jù)動作的類型來匹配的,那么我們可以用逆向思維,把合成器變成一個接受 state 和 action 兩個參數(shù)的純函數(shù)。也許還可以更簡單些,我們可以把動作規(guī)劃化,并且只傳遞狀態(tài)和一個數(shù)據(jù)載荷。
3. 使用 Async/Await 代替 Thunks在 Redux 中,Thunks最通用的做法就是用來創(chuàng)建異步動作。從多角度來看,這種用法更像是一個聰明的黑客所采用的用法,而不是一種官方推薦的用法。我們一步一步來看:
首先分發(fā)了一個動作,然而實(shí)際上卻是一個函數(shù)而不是期望的對象
Thunk 中間件檢查每一個動作,看它是否是一個函數(shù)
如果是函數(shù),那么中間件調(diào)用該函數(shù),同時把 dispatch 和 getState 方法傳參進(jìn)去
真的需要這樣么?把一個簡單的動作在運(yùn)行時識別為對象、函數(shù)甚至是 Promise,這難道不是糟糕的實(shí)踐么?
如上圖右邊所示,難道我們就不能只使用 async/await ?
4. 兩種類型的動作如果我們認(rèn)真想想的話,確實(shí)有兩種類型的動作:
合成器動作(Reducer action): 觸發(fā)合成器然后改變狀態(tài)
副作用動作(Effect action):觸發(fā)一個異步動作。這可能也稱為合成器動作,但是異步函數(shù)其實(shí)并沒有直接改變?nèi)魏螤顟B(tài)。
因此,把這兩種類型的動作區(qū)分開來會更有用,同時也不容易與 Thunks 搞混。
5. 不再需要定義動作類型變量為什么我們的標(biāo)準(zhǔn)實(shí)踐要把動作生成器和狀態(tài)合成器區(qū)分開來呢?能否只用其中一個呢?改變其中一個又是否會影響到另一個?
在我看來,動作生成器和狀態(tài)合成器就是硬幣的兩個面。
const ACTION_ONE = "ACTION_ONE" 可以說是把動作生成器和狀態(tài)合成器分開的冗余產(chǎn)物。如果我們把這兩者合二為一,那么就不會有那么多文件專門導(dǎo)出這些類型字符串了。
6. 合二為一的合成器按照使用方式,把 Redux 中所涉及的概念進(jìn)行合并分組,那么我們可以得出下面這個更簡單的模式。
在這種模式中,狀態(tài)合成器是可以自動確定與之對應(yīng)的動作生成器。因?yàn)椋藭r狀態(tài)合成器可以自動變成動作生成器。
通過簡單的命名約定,以下行為都會變得可預(yù)測:
如果狀態(tài)合成器命名為 increment,那么動作類型就是 increment。更好的做法是加上命名空間: count/increment。
每個動作都通過 payload 屬性來傳遞數(shù)據(jù)。
這樣的話,對于 count.increment,我們就可以自動的從狀態(tài)合成器推導(dǎo)出動作生成器。
好消息:更棒的 Redux以上的通電就是我們創(chuàng)建 Rematch 的原因。
Rematch 對 Redux 進(jìn)行了封裝,提供更簡單的 API,但又不失任何可配置性的特點(diǎn)。
下面是一個完整的使用例子:
我已經(jīng)把 Rematch 應(yīng)用在生成環(huán)境中有好幾個月了。作為小白鼠,我的體驗(yàn)是:
狀態(tài)管理從未變得如此簡單、高效。
Redux 并沒有被拋棄,而且也不應(yīng)該被拋棄。
只是,我們應(yīng)該以更低的學(xué)習(xí)成本,更少的樣板代碼和更少的認(rèn)知成本,來擁抱 Redux 背后的簡單哲學(xué)。
趕緊試一試 Rematch 吧!
萬一一不小心你就愛上它了呢?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/95498.html
摘要:應(yīng)用這說明并不是單指設(shè)計給用的,它是獨(dú)立的一個函數(shù)庫,可通用于各種應(yīng)用。在數(shù)據(jù)流的最后,要觸發(fā)最上層組件的,然后進(jìn)行整體的重新渲染工作。單純在的對象上是沒有辦法使用,要靠額外的函數(shù)庫才能這樣作,這是一定要使用類似像這種函數(shù)庫的主要原因。 Redux的官網(wǎng)中用一句話來說明Redux是什么: Redux是針對JavaScript應(yīng)用的可預(yù)測狀態(tài)容器 這句話雖然簡短,其實(shí)是有幾個涵義的: ...
摘要:沿著管道有兩組偵聽器中間件和訂閱。中間件是可以偵聽傳入的動作的函數(shù),支持諸如,或偵聽器之類的工具。將視為一個帶有更新前更新后鉤子的全局對象,以及能夠以簡單的方式合成新狀態(tài)。應(yīng)將兩者視為一體,并且不再需要文件導(dǎo)出類型的字符串。 難道現(xiàn)在狀態(tài)管理不是一個可以解決的問題嗎?直觀地說,開發(fā)人員似乎知道一個隱藏的事實(shí):狀態(tài)管理的使用似乎比需要的更困難。在本文中,我們將探討一些你可能一直在問自己的...
摘要:是一種前端狀態(tài)管理架構(gòu)思想,專門解決軟件的結(jié)構(gòu)問題?;诘脑O(shè)計思想,出現(xiàn)了一批前端狀態(tài)管理框架。他們給出了一些庫用于實(shí)現(xiàn)的思想,并在的基礎(chǔ)上做了一些改進(jìn)。在這些框架里,當(dāng)前最熱門的莫過于和了。 Flux Flux是一種前端狀態(tài)管理架構(gòu)思想,專門解決軟件的結(jié)構(gòu)問題。 基于Flux的設(shè)計思想,出現(xiàn)了一批前端狀態(tài)管理框架。他們給出了一些庫用于實(shí)現(xiàn)Flux的思想,并在Flux的基礎(chǔ)上做了一些改...
摘要:本周精讀內(nèi)容是重新思考。數(shù)據(jù)流對數(shù)據(jù)緩存,性能優(yōu)化,開發(fā)體驗(yàn)優(yōu)化都有進(jìn)一步施展的空間,擁抱插件生態(tài)是一個良好的發(fā)展方向。 本周精讀內(nèi)容是 《重新思考 Redux》。 1 引言 《重新思考 Redux》是 rematch 作者 Shawn McKay 寫的一篇干貨軟文。 dva 之后,有許多基于 redux 的狀態(tài)管理框架,但大部分都很局限,甚至是倒退。但直到看到了 rematch,總算...
摘要:關(guān)于的思考是一種前端狀態(tài)管理架構(gòu)思想,專門解決軟件的結(jié)構(gòu)問題。他們給出了一些庫用于實(shí)現(xiàn)的思想,并在的基礎(chǔ)上做了一些改進(jìn)。在這些框架里,當(dāng)前最熱門的莫過于和了。 關(guān)于Flux,Vuex,Redux的思考 Flux是一種前端狀態(tài)管理架構(gòu)思想,專門解決軟件的結(jié)構(gòu)問題。基于Flux的設(shè)計思想,出現(xiàn)了一批前端狀態(tài)管理框架。他們給出了一些庫用于實(shí)現(xiàn)Flux的思想,并在Flux的基礎(chǔ)上做了一些改進(jìn)。...
閱讀 1430·2021-09-22 15:00
閱讀 3365·2019-08-30 14:00
閱讀 1302·2019-08-29 17:27
閱讀 1289·2019-08-29 16:35
閱讀 770·2019-08-29 16:14
閱讀 2106·2019-08-26 13:43
閱讀 2188·2019-08-26 11:35
閱讀 2396·2019-08-23 15:34