近日,在一场关于JSX的讨论中,React核心成员「Sebastian Markbåge」(Hooks作者)表示:
他更推崇SwiftUI语法,并认为JSX就是个错误。
JSX最早由Facebook提出并推广,在React中被广泛用来描述视图状态。
作为一种类XML的JS语法糖,JSX同时兼顾了两个优点:
XML对树状结构优秀的表现力
不管是「嵌套」还是「属性」,JSX都能很自然的描述。
我们可以很容易从如下JSX结构推导出实际视图效果:
- <div style={{color: '#f00'}}>
- i am <span>Ka Song</span>
- </div>
JS在运行时的灵活
曾有人说:
- JSX就是拥有超能力的HTML
这里的超能力指:JSX作为JS语法糖,可以用JS语法灵活的描述视图状态。
- function App({children}) {
- return (
- <div>
- {children || 'i am empty'}
- </div>
- )
- }
作为对比,Vue模版语法的表现力就差很多。
然而,吾之蜜糖彼之砒霜:
受JS语法限制的XML
比如class属于JS语法keyword,而class在HTML中代表「类名」。
所以当JSX使用className作为「类名」的props时难免让人困惑。
- <div className="container"></div>
依赖编译
JSX需要先编译为JS才能在宿主环境执行,所以使用JSX描述视图的框架(比如React)都需要依赖编译工具。
这增加了项目环境配置的复杂度。
DSL哪家强?
到这里我们可以发现,衡量一门DSL(领域相关语言)优劣的标准有三点:
- 是否能直观描述视图状态
- 是否有灵活的编程能力
- 原生支持还是需要编译
让我们按这三个维度权衡几种不同平台的DSL:
HTML
视图描述能力:三星
编程能力:一星
不需要编译:一星
HTML描述视图能力最强(因为与DOM节点一一对应),但是缺乏编程能力。
Pug、Vue、JSX
视图描述能力:三星
编程能力:二到三星
都是在XML基础上演进的语法糖,拥有强大的描述视图能力。
他们的区别在于「编程能力」与「模版语法」的束缚之间取舍。
Flutter
视图描述能力:一星
编程能力:四星
使用函数调用的方式描述视图,编程能力很强。
但是在描述嵌套的组件树结构时,函数调用不如XML描述能力强。
比如如下HTML结构:
- <div>
- <p>Hello</p>
- <p>I am</p>
- <p>Ka Song</p>
- </div>
用Flutter语法描述:
- Stack(
- children: <Widget>[
- Text("Hello"),
- Text("I am"),
- Text("Ka Song")
- ],
- )
SwiftUI与React
SwiftUI作为被苹果寄予厚望、意图统领IOS全平台的DSL。
在保证强大的编程能力同时,也希望在视图表现力方面做的更好。
接下来我们通过一个简单的「点击加一」的计数器来对比React与SwiftUI语法:
React使用class语法:
- 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>数字:{counter}</p>
- <button onClick={this.increment}>点我加一</button>
- </>
- )
- }
- }
SwiftUI:
- struct Counter : View {
- @State var counter = 0
- func increment () {
- counter += 1
- }
- var body: some View {
- VStack {
- Text("数字: \(counter)")
- Button(action: increment) {
- Text("点我加一")
- }
- }
- }
- }
可以看到,抛开语法差异,两个框架的写法是很类似的。
同时,SwiftUI凭借强大的编程能力,原生实现React当前并不支持的功能:
比如,在React中,子组件要改变父组件的状态,需要父组件将「状态」与「改变状态的方法」传递给子组件。
子组件调用「改变状态的方法」通知父组件状态变化,父组件再传递变化后的「状态」给子组件。
这种方式在React中被称为「受控组件」。
在SwiftUI中,子组件只需要将父组件传递的状态申明为@Binding,就能达到与父组件该状态「双向绑定」的效果。
比如上例的counter:
- // 从
- @State var counter = 0
- // 变为
- @Binding var counter
则计数器接受父组件传递的counter状态,子组件counter状态改变后会作用于父组件counter状态。
你更喜欢哪种DSL
从2013年5月29日React诞生到现在。
经过8年的教育,大部分React开发者已经接受JSX。
但是,这期间也不断有人提出JSX的替代方案。
比如react-hyperscript。
随着SwiftUI热度提升,更是有人提出用其替代React中的JSX:
也有人做出模型experimental-react-like-framework
你喜欢JSX么?你觉得未来他会被谁取代?或者他会取代谁?
【编辑推荐】https://mp.weixin.qq.com/s/d73RPACWTGceWUXJuQe0RA