近日,在一場(chǎng)關(guān)于JSX的討論中,React核心成員「Sebastian Markbåge」(Hooks作者)表示:
他更推崇SwiftUI語(yǔ)法,并認(rèn)為JSX就是個(gè)錯(cuò)誤。
JSX最早由Facebook提出并推廣,在React中被廣泛用來(lái)描述視圖狀態(tài)。
作為一種類XML的JS語(yǔ)法糖,JSX同時(shí)兼顧了兩個(gè)優(yōu)點(diǎn):
XML對(duì)樹(shù)狀結(jié)構(gòu)優(yōu)秀的表現(xiàn)力
不管是「嵌套」還是「屬性」,JSX都能很自然的描述。
我們可以很容易從如下JSX結(jié)構(gòu)推導(dǎo)出實(shí)際視圖效果:
- <div style={{color: '#f00'}}>
- i am <span>Ka Song</span>
- </div>
JS在運(yùn)行時(shí)的靈活
曾有人說(shuō):
- JSX就是擁有超能力的HTML
這里的超能力指:JSX作為JS語(yǔ)法糖,可以用JS語(yǔ)法靈活的描述視圖狀態(tài)。
- function App({children}) {
- return (
- <div>
- {children || 'i am empty'}
- </div>
- )
- }
作為對(duì)比,Vue模版語(yǔ)法的表現(xiàn)力就差很多。
然而,吾之蜜糖彼之砒霜:
受JS語(yǔ)法限制的XML
比如class屬于JS語(yǔ)法keyword,而class在HTML中代表「類名」。
所以當(dāng)JSX使用className作為「類名」的props時(shí)難免讓人困惑。
- <div className="container"></div>
依賴編譯
JSX需要先編譯為JS才能在宿主環(huán)境執(zhí)行,所以使用JSX描述視圖的框架(比如React)都需要依賴編譯工具。
這增加了項(xiàng)目環(huán)境配置的復(fù)雜度。
DSL哪家強(qiáng)?
到這里我們可以發(fā)現(xiàn),衡量一門(mén)DSL(領(lǐng)域相關(guān)語(yǔ)言)優(yōu)劣的標(biāo)準(zhǔn)有三點(diǎn):
- 是否能直觀描述視圖狀態(tài)
- 是否有靈活的編程能力
- 原生支持還是需要編譯
讓我們按這三個(gè)維度權(quán)衡幾種不同平臺(tái)的DSL:
HTML
視圖描述能力:三星
編程能力:一星
不需要編譯:一星
HTML描述視圖能力最強(qiáng)(因?yàn)榕cDOM節(jié)點(diǎn)一一對(duì)應(yīng)),但是缺乏編程能力。
Pug、Vue、JSX
視圖描述能力:三星
編程能力:二到三星
都是在XML基礎(chǔ)上演進(jìn)的語(yǔ)法糖,擁有強(qiáng)大的描述視圖能力。
他們的區(qū)別在于「編程能力」與「模版語(yǔ)法」的束縛之間取舍。
Flutter
視圖描述能力:一星
編程能力:四星
使用函數(shù)調(diào)用的方式描述視圖,編程能力很強(qiáng)。
但是在描述嵌套的組件樹(shù)結(jié)構(gòu)時(shí),函數(shù)調(diào)用不如XML描述能力強(qiáng)。
比如如下HTML結(jié)構(gòu):
- <div>
- <p>Hello</p>
- <p>I am</p>
- <p>Ka Song</p>
- </div>
用Flutter語(yǔ)法描述:
- Stack(
- children: <Widget>[
- Text("Hello"),
- Text("I am"),
- Text("Ka Song")
- ],
- )
SwiftUI與React
SwiftUI作為被蘋(píng)果寄予厚望、意圖統(tǒng)領(lǐng)IOS全平臺(tái)的DSL。
在保證強(qiáng)大的編程能力同時(shí),也希望在視圖表現(xiàn)力方面做的更好。
接下來(lái)我們通過(guò)一個(gè)簡(jiǎn)單的「點(diǎn)擊加一」的計(jì)數(shù)器來(lái)對(duì)比React與SwiftUI語(yǔ)法:
React使用class語(yǔ)法:
- class Counter extends React.Component {
- state = {
- counter: 0
- }
- increment: () => {
- const {counter} = this.state;
- this.setState({counter: counter + 1})
- }
- render() {
- const {counter} = this.state;
- return (
- <>
- <p>數(shù)字:{counter}</p>
- <button onClick={this.increment}>點(diǎn)我加一</button>
- </>
- )
- }
- }
SwiftUI:
- struct Counter : View {
- @State var counter = 0
- func increment () {
- counter += 1
- }
- var body: some View {
- VStack {
- Text("數(shù)字: \(counter)")
- Button(action: increment) {
- Text("點(diǎn)我加一")
- }
- }
- }
- }
可以看到,拋開(kāi)語(yǔ)法差異,兩個(gè)框架的寫(xiě)法是很類似的。
同時(shí),SwiftUI憑借強(qiáng)大的編程能力,原生實(shí)現(xiàn)React當(dāng)前并不支持的功能:
比如,在React中,子組件要改變父組件的狀態(tài),需要父組件將「狀態(tài)」與「改變狀態(tài)的方法」傳遞給子組件。
子組件調(diào)用「改變狀態(tài)的方法」通知父組件狀態(tài)變化,父組件再傳遞變化后的「狀態(tài)」給子組件。
這種方式在React中被稱為「受控組件」。
在SwiftUI中,子組件只需要將父組件傳遞的狀態(tài)申明為@Binding,就能達(dá)到與父組件該狀態(tài)「雙向綁定」的效果。
比如上例的counter:
- // 從
- @State var counter = 0
- // 變?yōu)?nbsp;
- @Binding var counter
則計(jì)數(shù)器接受父組件傳遞的counter狀態(tài),子組件counter狀態(tài)改變后會(huì)作用于父組件counter狀態(tài)。
你更喜歡哪種DSL
從2013年5月29日React誕生到現(xiàn)在。
經(jīng)過(guò)8年的教育,大部分React開(kāi)發(fā)者已經(jīng)接受JSX。
但是,這期間也不斷有人提出JSX的替代方案。
比如react-hyperscript。
隨著SwiftUI熱度提升,更是有人提出用其替代React中的JSX:
也有人做出模型experimental-react-like-framework
你喜歡JSX么?你覺(jué)得未來(lái)他會(huì)被誰(shuí)取代?或者他會(huì)取代誰(shuí)?
【編輯推薦】https://mp.weixin.qq.com/s/d73RPACWTGceWUXJuQe0RA