欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Compose聲明式代碼語法對比React?Flutter?SwiftUI

 更新時(shí)間:2022年08月03日 10:53:26   作者:fundroid  
這篇文章主要為大家介紹了Compose聲明式代碼語法對比React?Flutter?SwiftUI來解釋為什么說?Compose?的聲明式代碼最簡潔,有需要的朋友可以借鑒參考下

前言

Comopse 與 React、Flutter、SwiftUI 同屬聲明式 UI 框架,有著相同的設(shè)計(jì)理念和相似的實(shí)現(xiàn)原理,但是 Compose 的 API 設(shè)計(jì)要更加簡潔。

本文就這幾個(gè)框架在代碼上做一個(gè)對比,感受一下 Compose 超高的代碼效率。

1.Stateless 組件

聲明式 UI 的基本特點(diǎn)是基于可復(fù)用的組件來構(gòu)建視圖,聲明式 UI 的開發(fā)過程本質(zhì)上就是各種 UI 組件的定義過程。組件在類型上一般分為無狀態(tài)的 Stateless 組件和有狀態(tài)的 Stateful 組件。

React 提供了類組件,函數(shù)式組件兩種組件定義方式:

//JS
function Greeting(props) {
  return <p>Hello, {props.name}</p>;
}
//JS
class Greeting extends React.Component {
  render() {
    return <p>Hello, {this.props.name}</p>;
  }
}

函數(shù)組件的數(shù)據(jù)通過 JS 函數(shù)參數(shù)傳遞;類組件通過 JSX 的標(biāo)簽屬性設(shè)置,并通過 Class 的 this.props 讀取。注意 props 不同于 state, 它是只讀的不可變化,這也是 Stateless 和 Stateful 的本質(zhì)區(qū)別。在代碼上函數(shù)式組件更加簡潔,避免了類定義帶來的模板代碼,因此,函數(shù)式組件在 React 中的使用占比越來越高。

類組件和函數(shù)組件也將聲明式 UI 框架劃分為兩個(gè)流派,F(xiàn)lutter 和 SwiftUI 屬于前者,而 Compose 屬于后者。這也從基礎(chǔ)上決定了 Compose 的組件的定義將更加簡潔。

讓我們分別看一下 Flutter 和 SwiftUI 的 Stateless 組件

//Dart
class Greeting extends StatelessWidget {
  const Greeting({required this.name});
  final String name;
  @override
  Widget build(BuildContext context) {
    return Text("Hello, $name");
  }
}

Flutter 使用類組件繼承的特性,通過 StatelessWidget 派生自定義 Stateless,然后定義構(gòu)造函數(shù)用來傳遞數(shù)據(jù)。build(BuildContext) 方法中通過實(shí)例化子組件并構(gòu)建 UI 。這還得感謝 Dart2 中對 new 關(guān)鍵字可以省略,不然構(gòu)造函數(shù)的調(diào)用代碼會更顯臃腫。

//Swift
struct Greeting: View {
    var name: String
    var body: some View {
        Text("Hello, \(name)")
    }
}

嚴(yán)謹(jǐn)?shù)卣f SwiftUI 組件不是類組件而是”結(jié)構(gòu)體組件”。Class 是引用類型,而 Struct 是值類型。使用結(jié)構(gòu)體定義組件有助于提升 UI 的不可變性,也是從面向?qū)ο笙蚝瘮?shù)式編程過度的一種體現(xiàn),但是結(jié)構(gòu)體組件從形式上更接近類組件,不如函數(shù)組件簡潔。

接下來看一下 Compose 的 Stateless:

//Kotlin
@Composable
fun Greeting(name: String) {
    Text("Hello $name")
}

Compose 的代碼明顯更簡潔,幾乎就是一個(gè)普通的函數(shù)定義,唯一的區(qū)別就是增加了一個(gè) @Composable 注解,這個(gè)注解在編譯期生成許多輔助框架運(yùn)行的代碼,開發(fā)者可以少些很多代碼,從代碼量的角度來看,次注解的性價(jià)比非常高。

即使同為函數(shù)組件的 React 相比,Compose 也更勝一籌,Composable 無論定義還是使用都是基于 Kotlin,使用體驗(yàn)更一致。而 React 的函數(shù)式組件需要在 JSX 中使用,雖然符合前端開發(fā)習(xí)慣,但是但從代碼復(fù)雜度上來說是不友好的。另外 Composable 沒有返回值,連 return 都省了,更簡潔。

Compose

React

2.Stateful 組件

React 的函數(shù)式組件使用 Hooks API 定義狀態(tài)

//JS
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <><button onClick={() => setCount(count + 1)}>
        {count}
      </button></>
  );
}

React Hooks 開創(chuàng)了聲明式 UI 狀態(tài)管理的新方式,相對于傳統(tǒng)的基于父類方法的方式代碼效率得到大幅提升。Compose 的狀態(tài)管理以及各種副作用 API 的設(shè)計(jì)靈感也來自 React Hooks. (參考:相似度99%?Jetpack Compose 與 React Hooks API對比

Flutter 中自定義 Stateful 組件是比較繁瑣的,首先 StatefulWidget 返回一個(gè) State d對象,Widget 定義在 State 中。

State 的變化觸發(fā) Widget 的重新構(gòu)建,這確實(shí)貫徹了狀態(tài)驅(qū)動(dòng) UI 的設(shè)計(jì)原則,但是增加了心智理解的成本。當(dāng)然,也有諸如 Flutter Hooks 這樣的三方庫可供使用,實(shí)現(xiàn)類似 React Hooks 的效果:

//Dart
class Counter extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final counter = useState(0);
    return TextButton(
      onPressed: () => counter.value++,
      child: Text("${counter.value}"),
    );
  }
}

SwiftUI 的 Stateful 的定義比較簡潔:

//Swift
struct Counter: View {
    @State var count = 0
    var body: some View {
        Button(
            action: { count += 1 },
            label: { Text("\(count)")}
        )
    }
}

使用 @State 注解定義一個(gè)成員變量,變量的變化可以自動(dòng)觸發(fā)界面刷新。

最后看一下 Compose 的 Stateful:

//Kotlin
@Composable
fun Counter() {
    val count by remember { mutableStateOf(0) }
    Button(
        onClick = { count++ }
    ) {
        Text("${count}")
    }
}

Compose 的 remember 本質(zhì)也是一種 Hooks 函數(shù),但是 Compose 的 Hooks 是用起來比起 React 更方便,在 React 中是用 Hooks 有諸多限制,例如下面這些用法都是不允許的。

  • 將 Hooks 函數(shù)放在條件分支里
//JS
if (flag) {
  const [count, setCount] = useState(0);
  ...
}

在子組件定義時(shí),使用 Hooks 函數(shù)

//JS
return (
  <div>
    {
      const [count, setCount] = useState(0);
      ...
    }
  </div>
)

在 Composable 中這些都不是問題,因?yàn)?Compose 獨(dú)有的 Positional Memoization 機(jī)制,可以根據(jù)靜態(tài)的代碼位置存儲狀態(tài),不會受到運(yùn)行時(shí)的分支條件變化的影響。另外 Compose 所有代碼都是同構(gòu)的,不會存在 JSX 無法插入 Hooks 的窘境,所以上面兩種 React 中的禁忌在 Compose 中都可以實(shí)現(xiàn):

//Kotlin
if (flag) {
    val count by remember { mutableStateOf(0) }
    ...
}
//Kotlin
Column {
    val count by remember { mutableStateOf(0) }
    ...
}

3. 控制流語句

我們經(jīng)常有根據(jù)分支條件顯示不同組件的需求,那么各個(gè)框架是如何在聲明式語法中中如何融入 if/for 等控制流語句的呢?

Compose 的函數(shù)式組件在這方面有天然優(yōu)勢,構(gòu)建 UI 的本質(zhì)就是一個(gè)函數(shù)實(shí)現(xiàn)的過程,過程中可以自然地插入控制流語句

//Kotlin
@Composable
fun List(value: List<Data>) {
    Column {
        Header()
        if (value.isEmpty()) {
            Empty()
        } else {
            value.forEach {
                Item(it) 
            }
        }
    }
}

上面的 Compose 例子中,通過 if..else 顯示不同結(jié)果,當(dāng)數(shù)據(jù)不為空時(shí),使用 for 循環(huán)依次展示,代碼非常直觀。

反觀 Flutter ,基于類組件的聲明式 UI 本質(zhì)上是不斷構(gòu)建對象的過程子組件通過構(gòu)造參數(shù)傳入,這個(gè)工程中插入控制流會比較復(fù)雜,上面同樣的 UI 在 Flutter 中寫會像下面這樣:

//Dart
@override
Widget build(BuildContext context) {
  List<Widget> widget;
  if (value.isEmtpy) {
      widget = Empty();
  } else {
      for (var i in value) {
          widget.add(i);
      }
  }
  return Column(children: [
    Header(),
    ...widget
  ]);
}

所幸,Dart 2.3 之后新增了 Collection-ifCollection-for,可以在 List 構(gòu)造中使用 if/for,代碼大大簡化:

//Dart
@override
Widget build(BuildContext context) {
  return Column(children: [
    Header(),
    if (value.isEmpty) Empty(),
    for (var i in value) Item(i)
  ]);
}

SwiftUI 原本應(yīng)該像類組件那樣通過對 Struct 的初始化添加子組件,但是它提供了 ViewBuilder 這樣的機(jī)制,可以使用 DSL 進(jìn)行 UI 構(gòu)建,和 Compose 幾乎無異

//Swift
var body: some View {
    VStack {
        Header()
        if value.isEmpty {
            Empty()
        }
        ForEach(value) {
            item inItem(item)
        }
    }
}

需要注意 ViewBuilder 中不能使用普通的控制流語句,ForEach 是針對 SwiftUI 定制的方法。

無論是 Flutter 還是 SwiftUI 他們的控制流語句都需要依賴一些定制語法或者語法糖,不像 Compose 那樣樸實(shí),代碼的可復(fù)用性也自然會受到影響。

最后簡單看一下 React 吧,同樣的邏輯實(shí)現(xiàn)如下

//JS
function List(value) {
    return (
        <div><Header />
            { value.isEmpty() && <Empty /> }
            { value.map((item) => <Item value={item} />) }
        </div>
    )
}

雖說是函數(shù)組件,但是添加子組件的邏輯不能用純 JS 實(shí)現(xiàn),需要在 JSX 定義,幸好 JSX 對這樣的控制流邏輯也有一些支持。

4. 生命周期

聲明式 UI 中都針對組件在視圖樹上的掛載/卸載定義了生命周期,并提供了響應(yīng) API。

React 類組件通過類的成員方法提供生命周期回調(diào),我們重點(diǎn)看一下函數(shù)組件的生命周期回調(diào)

//JS
useEffect(() => {
  const callback = new Callback()
  callback.register()
  return () => {
    callback.unregister()
  };
}, []);

useEffect 也是一種 Hooks 函數(shù),我們可以利用它監(jiān)聽組件的生命周期。最后返回的 lambda 是可以作為組件卸載時(shí)的回調(diào)。

Compose 參考 useEffect 提供了一系列副作用 API,以 DisposableEffect 為例

//Kotlin
DisposableEffect(Unit) {
    val callback = Callback()
    callback.register()
    onDispose {
        callback.unregister()
    }
}

設(shè)計(jì)上完全致敬 Hooks,最后 onDispose 是 Composable 從 Composition 中退出時(shí)的回調(diào)。

Flutter 作為類組件,自然是通過繼承自父類的方法回調(diào)生命周期

//Dart
class Sample extends StatefulWidget {
  @override
  _State createState() {
    return _State();
  }
}
class _State extends State<Sample> {
  final Callback _callback = Callback();
  @override
  Widget build(BuildContext context) {
    return ...;
  }
  @overridevoid initState() {
    super.initState();
    callback.register()
  }
  @overridevoid dispose() {
    super.dispose();
    callback.unregister()
  }
}

當(dāng)然,使用前面提到的 Flutter Hooks 的話,可以達(dá)到 React 與 Compose 的效果。

SwiftUI 的結(jié)構(gòu)體組件沒有繼承,所以通過 onAppearonDisappear 設(shè)置生命周期回調(diào)。相對于繼承的方式更加簡潔,但是它只能設(shè)置子組件的回調(diào),無法對當(dāng)前組件進(jìn)行設(shè)置。

//Swift
struct Sample: View {
    private let callback = Callback()
    var body: some View {
        Component()
            .onAppear(perform: {
                callback.register()
            })
            .onDisappear(perform: {
                callback.unregister()
            })
    }
}

綜上,React 和 Compose 的 Hooks 風(fēng)格的生命周期回調(diào)最為簡潔,因?yàn)閽燧d/卸載的回調(diào)可以在一個(gè)函數(shù)中完成,例如當(dāng)我們要往一個(gè) callback 實(shí)例上注冊/注銷回調(diào)時(shí),可以閉環(huán)完成操作,不必額外存儲這個(gè) callback 實(shí)例。

5. 裝飾/樣式

對比一下組件樣式的設(shè)置上 API 的區(qū)別,以最常用的 backgroundpadding 等為例。

React 基于 JSX 和 CSS-in-JS,可以像寫 HTML + CSS 那樣設(shè)置組件樣式,可以比較好地實(shí)現(xiàn) Style 與 Component 的解耦

//JS
const divStyle = {
  padding: '10px',
  backgroundColor: 'red',
};
return <div style={divStyle}>Hello World</div>;

Compose 通過 Modifier 為 Composable 設(shè)置樣式

//Kotlin
Text(
    text = "Hello World",
    modifier = Modifier
        .background(Color.Red)
        .padding(10.dp)
)

Flutter 通過 Widget 的構(gòu)造參數(shù)設(shè)置樣式,使用比較簡單,但是不具備 Modifier 的靈活性,不同 Widget 的 Style 無法復(fù)用。

//Dart
Container(
  color: Colors.red,
  padding: const EdgeInsets.all(10),
  child: Text("Hello World"),
)

SwiftUI 的樣式設(shè)置是基于組件實(shí)例的鏈?zhǔn)秸{(diào)用,非常簡單

//Swift
Text("Hello World")
  .padding(10)
  .background(Color.red)

綜上,在樣式設(shè)置上各家的 API 風(fēng)格都比較簡單,但是 Compose 的 Modifier 仍然具有不可比擬的優(yōu)勢,比如類型安全和容易復(fù)用等,Modifier 本身也是一種非常好的設(shè)計(jì)模式。

總結(jié)

前面基于代碼片段進(jìn)行了一些對比,最后以 Counter Demo 為例,看一個(gè)完整功能下 Flutter、Compose 和 Swift 的代碼對比,React 與其他三者代碼風(fēng)格差異較大,就不參加比較了。

Flutter

Compose

SwiftUI

可以感覺到 Compose 代碼最簡潔也最直觀,SwiftUI 通過 ViewBuilder 機(jī)制也可以實(shí)現(xiàn)與 Compose 類似的 DSL,表現(xiàn)也非常不錯(cuò),F(xiàn)lutter 由于模板代碼較多,在簡潔程度上表現(xiàn)最差。

Kotlin、Dart 和 Swift 的語法非常相近,所以拋開語言層面的差異,Compose 的優(yōu)勢主要還是來自于其采用了函數(shù)式的組件形式并借鑒了 React Hooks 的設(shè)計(jì)思想??梢哉f Compose 誕生于 React 的肩膀上,并借助 Kotlin 將代碼效率提升到一個(gè)新高度。

以上就是Compose聲明式代碼語法對比React Flutter SwiftUI的詳細(xì)內(nèi)容,更多關(guān)于Compose語法對比React Flutter SwiftUI的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解在swift中實(shí)現(xiàn)NSCoding的自動(dòng)歸檔和解檔

    詳解在swift中實(shí)現(xiàn)NSCoding的自動(dòng)歸檔和解檔

    本篇文章主要介紹了在swift中實(shí)現(xiàn)NSCoding的自動(dòng)歸檔和解檔,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Swift?并發(fā)修改Sendable?閉包實(shí)例詳解

    Swift?并發(fā)修改Sendable?閉包實(shí)例詳解

    這篇文章主要為大家介紹了Swift?并發(fā)修改Sendable?閉包實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 使用swift實(shí)現(xiàn)計(jì)算器功能

    使用swift實(shí)現(xiàn)計(jì)算器功能

    這篇文章主要為大家詳細(xì)介紹了使用swift實(shí)現(xiàn)計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 關(guān)于Swift 4.1中的Codable改進(jìn)詳解

    關(guān)于Swift 4.1中的Codable改進(jìn)詳解

    這篇文章主要給大家介紹了關(guān)于Swift 4.1中的Codable改進(jìn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-02-02
  • Combine中錯(cuò)誤處理和Scheduler使用詳解

    Combine中錯(cuò)誤處理和Scheduler使用詳解

    這篇文章主要為大家介紹了Combine中錯(cuò)誤處理和Scheduler使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Swift流程控制之循環(huán)語句和判斷語句詳解

    Swift流程控制之循環(huán)語句和判斷語句詳解

    這篇文章主要介紹了Swift流程控制之循環(huán)語句和判斷語句詳解,文中還使用了一個(gè)游戲例子來講解循環(huán)語句和判斷語句的使用,需要的朋友可以參考下
    2014-07-07
  • 使用Swift實(shí)現(xiàn)iOS App中解析XML格式數(shù)據(jù)的教程

    使用Swift實(shí)現(xiàn)iOS App中解析XML格式數(shù)據(jù)的教程

    這篇文章主要介紹了使用Swift實(shí)現(xiàn)iOS App中解析XML格式數(shù)據(jù)的教程,講到了iOS中提供的NSXMLParser和NSXMLParserDelegate兩個(gè)API的用法,需要的朋友可以參考下
    2016-04-04
  • swift如何利用系統(tǒng)庫將漢字轉(zhuǎn)換為拼音詳解

    swift如何利用系統(tǒng)庫將漢字轉(zhuǎn)換為拼音詳解

    將漢字轉(zhuǎn)換為拼音更利于我們大家開發(fā)搜索功能,所以這篇文章主要給大家介紹了關(guān)于swift如何利用系統(tǒng)庫將漢字轉(zhuǎn)換為拼音的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-10-10
  • SwiftUI智能家居開關(guān)燈頁面搭建示例

    SwiftUI智能家居開關(guān)燈頁面搭建示例

    這篇文章主要為大家介紹了SwiftUI智能家居開關(guān)燈頁面搭建示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 詳解Swift編程中的方法與屬性的概念

    詳解Swift編程中的方法與屬性的概念

    這篇文章主要介紹了Swift編程中的方法與屬性的概念,是Swift入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-11-11

最新評論