JSX有哪些缺陷?

React官方將JSX作為使用React的一項最佳實踐,但為什麼經常在社區或者博客看到有人對JSX表現出厭惡?


這個問題問得本身就有兩種理解,所以得分類討論:

第一個是很多人在答的:

你不喜歡 JSX 的範式(HTML in JS),你喜歡模版(或其它的)。

對,又是這個老生常談且無解的問題。你可以舉出一堆 HTML 和 JS 耦合在一起的糟糕情況,吐槽 JSX 是新的 PHP、JSP;你也同樣可以參考 React vs Angular 2: 冰與火之歌 - 前端外刊評論 - 知乎專欄 ,吐槽 DSL 相比 JSX 的弱小與局限。其實總結來總結去,不過是對 DOM 的兩種抽象,Announcing Vue.js 2.0 里已經講的夠清楚了:

Developers tend to have strong opinions on templates vs. JSX. On the one hand, templates are closer to HTML - they map better to the semantic structure of your app and make it much easier to think visually about the design, layout and styling. On the other hand, templates are limited to the DSL while the programmatic nature of JSX/hyperscript provides the full expressive power of a turing-complete language.

正所謂 「蘿蔔白菜,各有所愛」,Vue 2.0 乾脆把兩種都支持了完事兒。

而如果你反感 JSX 是因為反感 HTML in JS,那你大概也不會太喜歡 React,畢竟 React 處處都體現了它「以 JavaScript 為中心的設計」,就算不寫 JSX 你也要在 JS 里寫 AST 描述 DOM 的,何苦呢不是嗎,趁早換個框架吧。

而第二個可能更接近題主想問的(見問題描述),比如 @題葉 在答的:

在認同 React 範式的前提下,JSX 有什麼缺陷?

這可能才是一個有建設性的問題。在我們已經認同 React 以 JavaScript 為中心設計哲學的前提下,JSX 還有哪些可以改進的地方?

1. 沒有瀏覽器的原生支持 =&> 超高的工具鏈門檻

眾說周知,JSX 需要經過 Transform 才能在瀏覽器中運行,而有了 Babel 就要折騰工具鏈,跟我一起念!Build Process 有毒!ES6/ES2016 + ESLint + Webpack(etc.) + Redux + Hot Reload + React-Router + SSR 無論你需要不需要根本停不下來!看看滿天飛的 starter kit 就知道了,甚至還有 Find your perfect React starter project 這樣的項目,Welcome to JavaScript fatigue!

這對新手或者是寫 Demo/Snippet 的場景真的很煩,雖然 JSFiddle/JSBin 都提供了 JSX 的支持,但相比可以 Drop-in 直接在瀏覽器里跑起來的 Vue,還是不方便太多。Vue 不愧被稱為 「Progressive Framework」( Vue.js: 2015 in Review)

(怎麼老是忍不住給 Vue 打廣告…我明明用 React 用得更多 OTZ )

2. 不會成為規範

如 @題葉 所說,JSX 很容易挾帶 HTML 標準外的私貨,這是其一。其二是,Facebook 雖然起草了 JSX 的規範 https://github.com/facebook/jsx,但並不准備和 TC39 一起玩。Vue 2.0 已經支持了 JSX,並且可以想見在不遠的將來,還會有越來越多 JS 框架支持 JSX,還互不完全兼容。像 Web 這樣 open nature 的生態,規範都常年實現不清楚呢,不成為規範的就別提了想怎麼改怎麼改。當然,Templates 的語法已經百花齊放很久了。

3. JSX 中的邏輯表達不夠「優雅」,並且容易帶入個人風格

對於標籤和表達邏輯的 JS 混在一起不夠「優雅」這事,我倒還經常覺得模版 DSL 的各種奇怪符號不夠「優雅」呢……但容易帶入個人編碼風格這事是真的,相比模版來說更不利於團隊協作。不過哪一個表達能力強的語言沒這問題?大不了就上 JSX 的 Style Guide 咯:Airbnb React編碼規範 - 前端外刊評論 - 知乎專欄

除了上面三點外,還有一些相對模稜兩可的:

4. 既然都是 JavaScript 了,JSX 與 AST 哪個對開發者更友好?

雖然也踩過「不知道 JSX transform 出來的數據結構是啥」這樣的坑,不過整體上我還是傾向於 JSX 的,這種時候我們就要想想 markup 這種 DSL 的好:簡單、直觀、清晰、有助於描述 UI 結構和語義化。

5. JSX 與 Debug

關於 Debug,更是模稜兩可了。

從開發時角度看,JSX 可以在將代碼送至瀏覽器之前有一個檢查 typo 的機會(編譯時),而不像 templates 那樣到運行時才靜默報錯(詳見 React vs Angular 2: 冰與火之歌 - 前端外刊評論 - 知乎專欄 )

但另一方便,畢竟 React Components 在運行時 Inspect Elements 時是看不到的,增加了其他類型 bug 的 debug 的難度。雖然有 React Devtool 這樣的 Chrome Extension,但總是沒有親生的來得舒服,我還多次遇到過 Devtool 的 Bug,總之有那麼點 over-engineered 的意思。

仔細想想,JSX 在整個 React 體系中,其實也只是做了一點點微小的工作嘛,一直挑刺,很是慚愧啊,歡迎大家繼續補充。


稍微插一句無關的,按照 JSX 的規範(GitHub - facebook/jsx: The JSX specification is a XML-like syntax extension to ECMAScript.),特性名是可以使用 JavaScript 關鍵字的。。

(當然,JSX 本身只規定了語法,沒有規定語義)

只是 React 的 JSX 的 API 沒有使用並不是 JSX 不能用,就算沒有別的 JSX API 也是這樣。。

但是,現在明明就有別的 JSX API 呀,比如 Vue 2.0 的 JSX(GitHub - vuejs/babel-plugin-transform-vue-jsx: babel plugin for vue 2.0 jsx)就是直接使用的 class 而非 className。。

而且實際上 es5 就允許 JavaScript 關鍵字作為屬性名了的。。


Facebook 早年有一個叫 XHP 的技術,可以在 PHP 代碼里寫 HTML,有這樣的傳統 React 搞出 JSX 就不稀奇了。

我個人覺得,由於需要編譯導致開發者對最終瀏覽器運行的內容不可控的問題是存在的,但畢竟 JSX Transformer 本身也在不斷完善,出問題的可能太邊緣了,99.9% 的項目都不會被困擾,對於大部分追求 JSX 的便利性的人來講利遠大於弊。

不足有以下幾點:JSX 表達的是 Virtual DOM 而不是 HTML,所以它不是模板,概念理解上確實有點門檻;整個 JavaScript 技術體系更新快,一方面說明產業需求蓬勃,也反映出當年的設計和整個與之相關的生態太糙,而 web app 複雜度並不比 Android、iOS 等客戶端體系高,但直到現在還需要靠大量的新功能、新標準、新工具、polyfill 來彌補語言、平台本身的不足,導致構建流程過於複雜,JSX 讓這個問題雪上加霜,包括 debug 等等都需要專門的工具來支持,好在現在 source mapping 算是比較完善了不然連斷點調試、行號反溯都是坑。

最讓我困擾的是代碼太特么丑了,畢竟一個是 nested tag 用來描述結構,一個是 logic implementation 用來描述業務,markup 和編程語言放在一起怎麼看都彆扭,各種 Cody Style 指南也只是給一個統一的標準,就算丑讓大家醜成一個模子至少可以保證可維護性和可讀性,但從分離徹底、表述清晰的角度看 React 相比 web component style 的各種方案並不具備任何優勢,當然大家追求的東西也不一樣了。

最後還是那句話,沒有銀彈。各種解決方案有好就必有不好,多了解了解,根據項目需求和團隊狀況選擇才是正道。


作一個不是很恰當但有相關性的類比,用JSX碰到問題去翻文檔時候的那種感覺,讓我想起很久以前寫XSLT碰到問題去翻文檔的那種感覺。我覺得如果FB把它單純設計成template模式,從設計上更make sense,template是不用理解也能理解的那種模式。


不明白為什麼厭惡,jsx減少了大量繁雜的代碼。覺得不好的人可以嘗試創建一種更簡潔優美的dsl,如果確實能比jsx更簡潔,肯定會得到支持。


我個人的體驗…來說。

一開始寫的時候把它當模板用,之前使用underscore模板的,於是乎寫的模板一團漿糊。

還曾經抱怨,支持的內部js嵌套太淺了,哪怕寫一點複雜的className都挺噁心的。

後來一點點的,複雜className和style都在render return之前算好了,複雜一點的內部模板都抽出去做子組件了,整個render保持著比較簡單比較淺的層級,基本控制在兩屏以內。

後來醒悟jsx是展現你的組件結構的代碼,而不是用來顯示你的dom字元的代碼,所以,在react看來,你的組件粒度必須設計得足夠精確,才能保證程序不會亂掉或者難以維護。你的jsx里展現的主題應該是你的組件層級,而不是你組件內部的dom結構。

有時候覺得,正是因為jsx這種設計,逼迫自己寫代碼之前做好設計,你會發現其實從項目角度來看,不管是後續業務的修改還是復用,粒度細一點,對自己是很有好處的~當然不是吹jsx這樣有多優越,只是說它確實會敦促你去認真對待你的程序,不好好設計的代價就是寫出一團糟的不符合react範式的破玩意。而我們知道,使用react的目的是構件web app,而不是single web page,這事情需要走心的... 要是寫完即棄,那我恨不得就jquery插件全家桶了,要框架幹嘛。

當然,要是寫了這麼半天React,還沒有這些覺悟的話…其實用什麼框架都差不多,因為彼時需要的走心思考總結多讀多看,而不是糾結好不好。

ps,react官網文檔給出的結合underscore的寫法,其實蠻優雅的,只是覺得看的多了有點累…


感謝@Trotyl Yu評論指出,以下觀點只針對ReactReact的jsx,其他實現不在討論範圍。

看著像html其實返回js object,所以不少細節處有區別,在腦中需要translate增加思考成本。

- class是js reserved不能用所以要用className

- onclick不行一定要onClick還是綁到root component

- 寫個input找屬性查完mdn還得查React官網

- 同名的屬性不能省略要不然寫成

&

要不然寫成

&

兩種看著都丑。

JSX更多是照顧設計師和css程序員,所以討厭它的程序員還可以用這種方式

import { createElement as $ } from "react";

const Component = ({ propa, propb, childProp }) =&>

$("div", { propa, propb },

$(ChildComponent, { childProp })

);

看著是不是更functional了呢?


我很討厭 jsx。

jsx 導致 react 運行必須編譯。開了個壞頭,既然一定要用他的編譯器,就他夾點私貨進去也沒辦法,現在 babel 已經各種奇怪的東西在裡邊了。

新手學習的概念增多了。jsx 其實用數據類型來解釋不難的,加個語法。看似簡單了,但是對於熟悉編程的人來說,這種簡單本身把事情搞得更複雜。

jsx 沒有解決全部問題,statement 出現在代碼中很不舒服,有時也還是導致問題。

工具鏈變複雜,導致 coffeescript 等其他的方案需要被動支持甚至於被淘汰。不開心。

討厭歸討厭,既然人家成功了,總是有理由的。


算不上厭惡吧,只是喜歡不上來,即便我知道它不是htm in js而是ast,但是依然喜歡不上來

為什麼呢

因為我寫過JSP,維護過PHP站點,深知在一堆標籤跟條件語句里梳理出最終的HTML結構有多費勁。JSP裡面嵌套Java邏輯代碼然後生成變數bean被標籤引用,最後編譯成jspservlet形式的Java代碼,整個過程跟jsx不要太像!早前我聽說過react語法受到了PHP影響,結合fb又是PHP技術起家的背景,於是就秒懂了。。當然這個說法的真偽我沒求證過這裡當我抖機靈就好了。

總結來說就是,jsx跟模板引擎比雖然簡單沒有額外的語法,但是相應的也導致它表達能力有限,從而造成了邏輯跟標籤的碎片化,而人腦對上下文的記憶能力又一般,導致整個代碼的可讀性變差,維護起來就會吃力。雖然合理的組件拆分會增加表達能力降低維護成本,但是本質問題還是存在的。

以上


理念是非常先進的,這點我承認,越複雜,交互越多,中間狀態越多的場景,React的理念越能發揮作用。

但有兩個最主要的問題:

1、周邊零散的工具太多,什麼都能做,但總體開發體驗不太好,比較難與已有的工具集成。

2、較難利用已有的積累,基本上什麼都要從零造一次。


可維護性差,很容易寫成大量 js 和大量 html 混雜的代碼,各自碎片化,閱讀起來很吃力。


看了其它的答案並沒有特別好的理由。

可維護性差:分出若干 Component,傳入 props 確定時,渲染結果也是確定的,測試很方便,閱讀的時候也很好找到目標模塊。

需要編譯:就算不用 jsx,現在使用 es6 語法的話,各種 import、箭頭函數、const 這些都是需要編譯的,後期還需要打包合併這些。

表達能力有限:有了 js 的幫襯不應該存在這個問題吧?反而我用模版的時候寫 if else, repeat 這些簡單邏輯的還沒問題,稍微複雜點,模板就比較難看了。

為了 wrap 而 wrap 的標籤:這個我確實也遇到了。

睡覺去了(? ̄△ ̄)?


他們還不習慣、思想沒轉變、思想不想轉變、固有經驗逆反、總之不是 JSX 的鍋、你可以不用啊 對不對


JSX不是模板,但大家根據以往經驗,會自動把他看成模板,但很多細節和模板都是不一樣的。

而且萬惡的,居然和js放一起。。

為啥寫ExtJS不會覺得組件使用寫在JS有啥不對?

如果用JSX寫ExtJS會不會更爽?


如果沒有jsx。我也許會更喜歡react


只說一點, 為什麼photoshop這種設計工具不做成用代碼拼的而是用圖形畫的? 一切只從開發角度而不從設計角度設計界面語言都是耍流氓, 這也是為什麼flash 發明了mxml, iOS的storyboard, 和一大堆類xml, uml 界面語言. 不是DSL有多好,而是用程序語言設計界面本身就是錯誤的和低效的思想. JSX還想逆潮流而上, javascript為中心? 怪不得facebook的界面做的很簡單,動畫幾乎沒有, react整個社區UI組件匱乏的比backbone都差, 都是jsx和react的惹的禍.


jsx 是一種 js 的 DSL 吧, 兼具了 聲明式 和 命令式的 優點


目前感觸比較深的一點就是,JSX對DOM事件的支持程度又回到了解放前,要想實現比較複雜的事件監聽,代碼量不小


jsx就是使用JavaScript的強大功能來供你寫UI。因為使用了JavaScript,所以你不用記任何標籤語法,唯一你需要記住的可能就是className替代了class熟悉,htmlFor替代了for熟悉,另外綁定事件名稱要採用駱駝命名法,比如onClick。對了,因為是JavaScript,所以添加行樣式時候採用對象的形式,比如style={{width: "calc(100% - 20px)", marginLeft: "20px"}},僅此而已。

對於外界一直吐槽的只能返回一個節點的問題,最新發布的16版本中也增加了返回數組元素了。

所以jsx寫的不要太爽,我只要記住js語法就可以了,啥模板標籤全滾蛋。不知道為啥有那麼多人吐槽。


缺陷是很多人駕馭不了


推薦閱讀:

Vue 官網上的這個圖是用什麼工具畫的?
為什麼直接修改數組長度或設置數組項的索引時,Vue不能檢測到數組的變動?
做為一個初級前端,我要花多久時間學習vue才能在項目中用它?
vue子組件用父組建方法改變執行上下文環境的問題?

TAG:前端開發 | JavaScript | 前端框架 | React |