為什么 ReactJS 不適合復(fù)雜的前端項(xiàng)目酪耳?

《More than React》系列的文章會(huì)一共分為五篇。本文是第一篇刹缝,介紹用ReactJS開發(fā)時(shí)遇到的種種問題碗暗。后面四篇文章的每一篇將會(huì)分別詳細(xì)討論其中一個(gè)問題颈将,以及Binding.scala如何解決這個(gè)問題。

背景介紹

去年 4 月讹堤,我第一次在某個(gè)客戶的項(xiàng)目中接觸到ReactJS 吆鹤。

我發(fā)現(xiàn)ReactJS要比我以前用過的AngularJS簡單很多,它提供了響應(yīng)式的數(shù)據(jù)綁定功能洲守,把數(shù)據(jù)映射到網(wǎng)頁上疑务,使我可以輕松實(shí)現(xiàn)交互簡單的網(wǎng)站。

然而梗醇,隨著我越來越深入的使用ReactJS知允,我發(fā)現(xiàn)用ReactJS編寫交互復(fù)雜的網(wǎng)頁很困難。
我希望有一種方式叙谨,能夠像ReactJS一樣簡單解決簡單問題温鸽。此外,還要能簡單解決復(fù)雜問題手负。

于是我把ReactJS用Scala重新寫了一個(gè)涤垫。代碼量從近三萬行降到了一千多行。

用這個(gè)框架實(shí)現(xiàn)的TodoMVC應(yīng)用竟终,只用了154行代碼蝠猬。而用ReactJS實(shí)現(xiàn)相同功能的TodoMVC,需要488行代碼统捶。

下圖是用Binding.scala實(shí)現(xiàn)的TodoMVC應(yīng)用榆芦。

這個(gè)框架就是Binding.scala

問題一:ReactJS組件難以在復(fù)雜交互頁面中復(fù)用

ReactJS中的最小復(fù)用單位是組件喘鸟。ReactJS的組件比AngularJS的Controller和View 要輕量些匆绣。
每個(gè)組件只需要前端開發(fā)者提供一個(gè) render 函數(shù),把 propsstate 映射成網(wǎng)頁元素什黑。

這樣的輕量級(jí)組件在渲染簡單靜態(tài)頁面時(shí)很好用崎淳,
但是如果頁面有交互,就必須在組件間傳遞回調(diào)函數(shù)來處理事件愕把。

我將在《More than React(二)組件對復(fù)用性有害凯力?》中用原生DHTML API、ReactJS和Binding.scala實(shí)現(xiàn)同一個(gè)需要復(fù)用的頁面礼华,介紹Binding.scala如何簡單實(shí)現(xiàn)咐鹤、簡單復(fù)用復(fù)雜的交互邏輯。

問題二:ReactJS的虛擬DOM 算法又慢又不準(zhǔn)

ReactJS的頁面渲染算法是虛擬DOM差量算法圣絮。

開發(fā)者需要提供 render 函數(shù)祈惶,根據(jù) propsstate 生成虛擬 DOM。
然后 ReactJS 框架根據(jù) render 返回的虛擬 DOM 創(chuàng)建相同結(jié)構(gòu)的真實(shí) DOM.

每當(dāng) state 更改時(shí),ReacJS 框架重新調(diào)用 render 函數(shù)捧请,獲取新的虛擬 DOM 凡涩。
然后,框架會(huì)比較上次生成的虛擬 DOM 和新的虛擬 DOM 有哪些差異疹蛉,然后把差異應(yīng)用到真實(shí)DOM上活箕。

這樣做有兩大缺點(diǎn):

  1. 每次 state 更改,render 函數(shù)都要生成完整的虛擬 DOM. 哪怕 state 改動(dòng)很小可款,render函數(shù)也會(huì)完整計(jì)算一遍育韩。如果 render 函數(shù)很復(fù)雜,這個(gè)過程就白白浪費(fèi)了很多計(jì)算資源闺鲸。
  2. ReactJS框架比較虛擬DOM差異的過程筋讨,既慢又容易出錯(cuò)。比如摸恍,假如你想要在某個(gè) <ul> 列表的頂部插入一項(xiàng) <li> 悉罕,那么ReactJS框架會(huì)誤以為你修改了 <ul> 的每一項(xiàng) <li>,然后在尾部插入了一個(gè) <li>立镶。

這是因?yàn)?ReactJS收到的新舊兩個(gè)虛擬DOM之間相互獨(dú)立壁袄,ReactJS并不知道數(shù)據(jù)源發(fā)生了什么操作,只能根據(jù)新舊兩個(gè)虛擬DOM來猜測需要執(zhí)行的操作媚媒。
自動(dòng)的猜測算法既不準(zhǔn)又慢然想,必須要前端開發(fā)者手動(dòng)提供 key 屬性、shouldComponentUpdate 方法欣范、componentDidUpdate 方法或者 componentWillUpdate 等方法才能幫助 ReactJS 框架猜對。

我將在《More than React(三)虛擬DOM已死令哟?》中比較ReactJS恼琼、AngularJS和Binding.scala渲染機(jī)制,介紹簡單性能高的Binding.scala精確數(shù)據(jù)綁定機(jī)制屏富。

問題三:ReactJS的HTML模板功能既不完備晴竞、也不健壯

ReactJS支持用JSX編寫HTML模板。

理論上狠半,前端工程師只要把靜態(tài)HTML原型復(fù)制到JSX源文件中噩死,
增加一些變量替換代碼,
就能改造成動(dòng)態(tài)頁面神年。
理論上這種做法要比Cycle.js已维、Widok、ScalaTags等框架更適合復(fù)用設(shè)計(jì)師提供的HTML原型已日。

不幸的是垛耳,ReactJS對HTML的支持殘缺不全。開發(fā)者必須手動(dòng)把classfor屬性替換成classNamehtmlFor,還要把內(nèi)聯(lián)的style樣式從CSS語法改成JSON語法堂鲜,代碼才能運(yùn)行栈雳。
這種開發(fā)方式下,前端工程師雖然可以把HTML原型復(fù)制粘貼到代碼中缔莲,但還需要大量改造才能實(shí)際運(yùn)行哥纫。
比Cycle.js、Widok痴奏、或者蛀骇、ScalaTags省不了太多事。

除此之外抛虫,ReactJS還提供了propTypes機(jī)制校驗(yàn)虛擬DOM的合法性松靡。
然而,這一機(jī)制也漏洞百出建椰。
即使指定了propTypes雕欺,ReactJS也不能在編譯前提前發(fā)現(xiàn)錯(cuò)誤。只有測試覆蓋率很高的項(xiàng)目時(shí)才能在每個(gè)組件使用其他組件時(shí)進(jìn)行校驗(yàn)棉姐。
即使測試覆蓋率很高屠列,propTypes仍舊不能檢測出拼錯(cuò)的屬性名,如果你把onClick寫成了onclick伞矩,
ReactJS就不會(huì)報(bào)錯(cuò)笛洛,往往導(dǎo)致開發(fā)者額外花費(fèi)大量時(shí)間排查一個(gè)很簡單的bug。

我將在《More than React(四)HTML也可以編譯乃坤?》中比較ReactJS和Binding.scala的HTML模板苛让,介紹Binding.scala如何在完整支持XHTML語法的同時(shí)靜態(tài)檢查語法錯(cuò)誤和語義錯(cuò)誤。

問題四:ReactJS與服務(wù)器通信時(shí)需要復(fù)雜的異步編程

ReactJS從服務(wù)器加載數(shù)據(jù)時(shí)的架構(gòu)可以看成MVVM(Model–View–ViewModel)模式湿诊。
前端工程師需要編寫一個(gè)數(shù)據(jù)庫訪問層作為Model狱杰,把ReactJS的state當(dāng)做ViewModel,而render當(dāng)做View厅须。
Model負(fù)責(zé)訪問數(shù)據(jù)庫并把數(shù)據(jù)設(shè)置到state(即View Model)上仿畸,可以用Promise和fetch API實(shí)現(xiàn)。
然后朗和,render错沽,即View,負(fù)責(zé)把View Model渲染到頁面上眶拉。

在這整套流程中千埃,前端程序員需要編寫大量閉包組成的異步流程,
設(shè)置忆植、訪問狀態(tài)的代碼五零四散镰禾,
一不小心就會(huì)bug叢生皿曲,就算小心翼翼的處理各種異步事件,也會(huì)導(dǎo)致程序變得復(fù)雜吴侦,既難調(diào)試屋休,又難維護(hù)。

我將在《More than React(五)為什么別用異步編程备韧?》中比較ReactJS和Binding.scala的數(shù)據(jù)同步模型劫樟,介紹Binding.scala如何自動(dòng)同步服務(wù)器數(shù)據(jù),避免手動(dòng)異步編程织堂。

結(jié)論

盡管Binding.scala初看上去很像ReactJS叠艳,
但隱藏在Binding.scala背后的機(jī)制更簡單允瞧、更通用烹玉,與ReactJS和Widok截然不同。

所以锨络,通過簡化概念潦俺,Binding.scala靈活性更強(qiáng)拒课,能用通用的方式解決ReactJS解決不了的復(fù)雜問題。

比如事示,除了上述四個(gè)方面以外早像,ReactJS的狀態(tài)管理也是老大難問題,如果引入Redux或者react-router這樣的第三方庫來處理狀態(tài)肖爵,會(huì)導(dǎo)致架構(gòu)變復(fù)雜卢鹦,分層變多,代碼繞來繞去劝堪。而Binding.scala可以用和頁面渲染一樣的數(shù)據(jù)綁定機(jī)制描述復(fù)雜的狀態(tài)冀自,不需要任何第三方庫,就能提供服務(wù)器通信秒啦、狀態(tài)管理和網(wǎng)址分發(fā)的功能熬粗。

以下表格中列出了上述Binding.scala和ReactJS的功能差異:

3-sheet.png

兩個(gè)多月前,我在Scala.js的論壇發(fā)布Binding.scala時(shí)帝蒿,當(dāng)時(shí)Scala.js社區(qū)最流行的響應(yīng)式前端編程框架是Widok。Tim Nieradzik是Widok的作者巷怜。他在看到我發(fā)布的框架后葛超,稱贊這個(gè)框架是Scala.js社區(qū)最有前途的 HTML 5渲染框架。

他是對的延塑,兩個(gè)月后绣张,現(xiàn)在Binding.scala已經(jīng)成為Scala.js社區(qū)最流行的響應(yīng)式前端編程框架。

Awesome Scala網(wǎng)站對比了Scala的響應(yīng)式前端編程框架关带,Binding.scala的活躍程度和流行度都比Udash侥涵、Widok等其他框架要高沼撕。

我在最近的幾個(gè)項(xiàng)目中,也逐漸放棄JavaScript和ReactJS芜飘,改用Scala.js和Binding.scala搭建新時(shí)代的前端技術(shù)棧务豺。

相關(guān)鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嗦明,隨后出現(xiàn)的幾起案子笼沥,更是在濱河造成了極大的恐慌,老刑警劉巖娶牌,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奔浅,死亡現(xiàn)場離奇詭異,居然都是意外死亡诗良,警方通過查閱死者的電腦和手機(jī)汹桦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鉴裹,“玉大人舞骆,你說我怎么就攤上這事∫挤#” “怎么了葛作?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長猖凛。 經(jīng)常有香客問我赂蠢,道長,這世上最難降的妖魔是什么辨泳? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任虱岂,我火速辦了婚禮,結(jié)果婚禮上菠红,老公的妹妹穿的比我還像新娘第岖。我一直安慰自己,他們只是感情好试溯,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布蔑滓。 她就那樣靜靜地躺著,像睡著了一般遇绞。 火紅的嫁衣襯著肌膚如雪键袱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天摹闽,我揣著相機(jī)與錄音蹄咖,去河邊找鬼。 笑死付鹿,一個(gè)胖子當(dāng)著我的面吹牛澜汤,可吹牛的內(nèi)容都是我干的蚜迅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼俊抵,長吁一口氣:“原來是場噩夢啊……” “哼谁不!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起务蝠,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤拍谐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后馏段,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轩拨,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年院喜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了亡蓉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喷舀,死狀恐怖砍濒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情硫麻,我是刑警寧澤爸邢,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站拿愧,受9級(jí)特大地震影響杠河,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浇辜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一券敌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柳洋,春花似錦待诅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至绪囱,卻和暖如春测蹲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背毕箍。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工弛房, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留道盏,地道東北人而柑。 一個(gè)月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓文捶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親媒咳。 傳聞我的和親對象是個(gè)殘疾皇子粹排,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容