Modal.confirm是否違反了React模式分析
引言
如何評(píng)價(jià) Ant Design 這個(gè)項(xiàng)目(一個(gè)設(shè)計(jì)語(yǔ)言)?
這是一篇臨時(shí)起意的文章,我參與了一點(diǎn)上圖中的討論,正好有點(diǎn)時(shí)間,索性拉篇文章專門聊聊。
首先說(shuō)結(jié)論:我不認(rèn)為Modal.confirm以及類似的API是anti-pattern,盡管antd作者
@偏右悄悄地 也說(shuō)Modal.confirm“并不符合React哲學(xué)”。
什么是“React模式”?
很多人都見(jiàn)過(guò)這個(gè)公式——
view = f(data)
React確實(shí)就是這么運(yùn)作的。
然而React從來(lái)沒(méi)有建議過(guò),讓你的整個(gè)應(yīng)用都這么運(yùn)作。很顯然,一個(gè)view=f(data),是涵蓋不了前端應(yīng)用那么多可能性的。那么一個(gè)現(xiàn)實(shí)中有用的網(wǎng)頁(yè),大致應(yīng)該怎么運(yùn)作?
看圖說(shuō)話——
這張圖我想所有人都能看懂,大部分給你科普前端架構(gòu)的文章大致都是這么畫(huà)的,這里只解釋兩點(diǎn):
- 第一,藍(lán)箭頭代表狀態(tài)傳遞,紅箭頭代表行為傳遞。比如vdom,其實(shí)就是一堆描述某一時(shí)刻html狀態(tài)的數(shù)據(jù),但是經(jīng)過(guò)diff,得到的指導(dǎo)react-dom進(jìn)行操作的patch,其實(shí)描述的是“行為”,用現(xiàn)在時(shí)髦的說(shuō)法叫“副作用”。
- 紅框里面為什么除了data還有timing?timing指的是時(shí)機(jī),就是說(shuō)你什么時(shí)候應(yīng)該渲染,本質(zhì)上是model那一層告訴你的,React組件不會(huì)自己沒(méi)事兒渲染著玩(先不考慮state)。
圖是很美好,然而如果一個(gè)網(wǎng)頁(yè)就這樣的話,它除了展示一下畫(huà)面(還不能做單頁(yè)),不會(huì)有任何用處。所以這個(gè)圖要完善一下——
經(jīng)過(guò)完善,圖里面多了框,就是紅框里那個(gè)actions,指的是當(dāng)你點(diǎn)按鈕的時(shí)候,發(fā)生的回調(diào)操作。有的框架里面管這個(gè)叫action,有的是store的成員函數(shù),還有的比如redux,雖然它有action概念,但其實(shí)真正的“action”是在reducer里面實(shí)現(xiàn)的。
另外這里又出現(xiàn)了timing(時(shí)機(jī)),這其實(shí)是我最近很喜歡的一個(gè)概念。所謂的timing,就是告訴另一個(gè)模塊“it’s time to do xxx”,trigger(event)是timing,dispatch(action)是timing,甚至直接調(diào)用成員函數(shù),其實(shí)也是一種timing。
這張圖,看起來(lái)能干一些事兒了,至少能點(diǎn)按鈕刷新數(shù)據(jù)了,能做單頁(yè)了。然而我們的網(wǎng)頁(yè),并非是只讀的,除了展示數(shù)據(jù),還要往后臺(tái)提交數(shù)據(jù),或者執(zhí)行某個(gè)具體的功能(比如VScode里點(diǎn)ctrl+s保存,它需要往硬盤里面寫(xiě)文件)。所以還要完善一下——
相對(duì)完整的前端應(yīng)用架構(gòu)
哎,這個(gè)版本看起來(lái)有具體功能了,因?yàn)槌藶g覽器html之外,我們還多了個(gè)“IO等”,這樣那些除了變動(dòng)html之外的“副作用”,就可以實(shí)現(xiàn)了?;旧弦粋€(gè)網(wǎng)頁(yè)的架構(gòu),就是這樣了。
注意,在這個(gè)版本中,Model也可以調(diào)用Actions,這是因?yàn)橛行㎝odel庫(kù)是響應(yīng)式的,比如rx,它本身就可以通過(guò)subscribe驅(qū)動(dòng)副作用。
到這里,咱們終于可以進(jìn)正題了。
我在上面的圖中花了三個(gè)虛線框,中間那個(gè)是“React掌管的部分”,也就是建議view=f(data)那部分。我們看下箭頭的顏色,Model到View,應(yīng)該是狀態(tài)數(shù)據(jù)(data),View到Actions,應(yīng)該是行為指令(timing)。
其他兩層,天生就不是React掌管的范圍,業(yè)務(wù)模型主要負(fù)責(zé)維護(hù)數(shù)據(jù)以及數(shù)據(jù)之間的驅(qū)動(dòng)關(guān)系,Side effect backend主要負(fù)責(zé)實(shí)現(xiàn)各種副作用,React的那套模型,在這里幫不上忙——注意,這不代表那兩層就完全不能用React,事實(shí)上confirm完全可以理解為IO的一種(類比下c語(yǔ)言的scanf)。
也就是說(shuō),哪怕一個(gè)帶有明顯數(shù)據(jù)驅(qū)動(dòng)特色的React項(xiàng)目,也存在很多部分不是數(shù)據(jù)驅(qū)動(dòng)而是事件驅(qū)動(dòng)的(我更喜歡成為“時(shí)機(jī)驅(qū)動(dòng)”),這是天經(jīng)地義的事情,不然你的程序根本寫(xiě)不出來(lái)。原因很簡(jiǎn)單,數(shù)據(jù)只能驅(qū)動(dòng)出狀態(tài),只有時(shí)機(jī)才能驅(qū)動(dòng)出行為——學(xué)過(guò)《數(shù)電》應(yīng)該對(duì)這一點(diǎn)深有感觸。
那么,對(duì)于“用戶點(diǎn)擊刪除按鈕,彈出確認(rèn)框,點(diǎn)擊確定刪除條目,點(diǎn)擊取消不做任何操作”這樣一個(gè)功能——
- 你覺(jué)得他是個(gè)狀態(tài)還是個(gè)行為?
- 你覺(jué)得他是時(shí)機(jī)驅(qū)動(dòng)的還是數(shù)據(jù)驅(qū)動(dòng)的?
答:它是個(gè)行為,時(shí)機(jī)驅(qū)動(dòng)。
那么,對(duì)于一個(gè)時(shí)機(jī)驅(qū)動(dòng)的行為,你非得把它硬坳成一個(gè)數(shù)據(jù)驅(qū)動(dòng)的狀態(tài),你不覺(jué)得很奇怪嗎?
一個(gè)comfirm,這么寫(xiě)有什么問(wèn)題呢(偽代碼,忽略一部分保護(hù)性代碼)?
class FoobarComponent extends React.Component { // ... async onRemoveBtnClick (id) { const yes = await Modal.confirm('確認(rèn)刪除嗎?') if (!yes) return dispatch(actions.remove({ id })) } render () { const { items } = this.props return <ul> { items.map(el => <li key={el.id}> <span>{el.name}</span> <button onClick={this.onRemoveBtnClick.bind(this, el.id)}>刪除</button> </li>) } </ul> } }
那么,為什么有人會(huì)覺(jué)的這樣寫(xiě)是反模式呢?
我覺(jué)得可能是因?yàn)槲覀冊(cè)诰帉?xiě)網(wǎng)頁(yè)的時(shí)候,一般都會(huì)比較注重縱向分層,卻常常忽視橫向切分。由于react-router的盛行,基本上我們是在組件這個(gè)層面配合前端路由來(lái)做橫向切分的,但實(shí)際上這只是一種特殊情況,如果我們的應(yīng)用更復(fù)雜,我們可能需要這樣的結(jié)構(gòu)——
上圖中每個(gè)模塊,都和模塊A具有大致相同的結(jié)構(gòu),各個(gè)模塊之間的時(shí)機(jī)和狀態(tài),可以通過(guò)總線一類的工具來(lái)中轉(zhuǎn)。
如果我們寫(xiě)網(wǎng)頁(yè)的“起手式”就是這樣的,那么Modal,可能會(huì)被設(shè)計(jì)成一個(gè)單獨(dú)的模塊M,Modal.comfirm,可能會(huì)被設(shè)計(jì)成這樣:
const yes = await globalBus.dispachAndWait(Actions.comfirm('確認(rèn)刪除嗎?'))
這樣,你還會(huì)覺(jué)得“反模式”嗎?
PS:為什么為這件小事兒?jiǎn)逻@么一大篇文章呢?其實(shí)這本來(lái)也是我2018年前端技術(shù)總結(jié)的一部分想法,只是臨時(shí)借著這個(gè)討論說(shuō)出來(lái)了。2018年上半年,參與了一個(gè)臨時(shí)前端團(tuán)隊(duì),堆了不少業(yè)務(wù)表單頁(yè)面,期間,我跟人強(qiáng)調(diào)了無(wú)數(shù)次“不要無(wú)腦數(shù)據(jù)驅(qū)動(dòng)”,還是有有人非得閃轉(zhuǎn)騰挪用數(shù)據(jù)驅(qū)動(dòng)和render表達(dá)一切,留了一大堆屎給我重構(gòu),我這一股無(wú)名火憋到現(xiàn)在。
以上就是Modal.confirm是否違反了React模式分析的詳細(xì)內(nèi)容,更多關(guān)于React模式剖析Modal.confirm的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
ReactNative實(shí)現(xiàn)圖片上傳功能的示例代碼
本篇文章主要介紹了ReactNative實(shí)現(xiàn)圖片上傳功能的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-07-07React-hook-form-mui基本使用教程(入門篇)
react-hook-form-mui可以幫助開(kāi)發(fā)人員更輕松地構(gòu)建表單,它結(jié)合了React?Hook?Form和Material-UI組件庫(kù),使用react-hook-form-mui,開(kāi)發(fā)人員可以更快速地構(gòu)建表單,并且可以輕松地進(jìn)行表單驗(yàn)證和數(shù)據(jù)處理,本文介紹React-hook-form-mui基本使用,感興趣的朋友一起看看吧2024-02-02react-pdf?打造在線簡(jiǎn)歷生成器的示例代碼
本文主要介紹了react-pdf?打造在線簡(jiǎn)歷生成器的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02