😺

React,JetpackCompose,SwiftUIの比較

2024/10/22に公開

ページの目的

React,JetpackComposeでの開発をしてきたが、SwiftUIでの開発をする必要が出てきたでので、ReactやJetpackComposeと比較することでSwitUIでの実装のイメージをつける。

概要

React,JetpackCompose,SwiftUIの比較をAIに比較してもらった。

機能

機能 React Jetpack Compose SwiftUI
使用言語 JavaScript, TypeScript Kotlin Swift
プラットフォーム Web Android iOS, macOS, watchOS, tvOS
宣言型UI はい はい はい
コンポーネントベース はい はい はい
状態管理 useState, useReducer, Context API remember, MutableState @State, @Binding, @ObservedObject
再利用可能なUIコンポーネント はい はい はい
レイアウトシステム Flexbox ConstraintLayout, Row, Column VStack, HStack, ZStack
ネイティブAPIアクセス ライブラリ (React Native で可能) 直接アクセス可能 直接アクセス可能
ホットリロード はい (React Fast Refresh) はい (Live Edit) はい (Previews)
コード共有 WebとReact Native間で可能 Android間で共有可能 Appleエコシステム間で共有可能
UIのアニメーション CSSまたはJavaScriptライブラリ Modifierでサポート .animation()でサポート
カスタムジェスチャー対応 ライブラリ(React Native Gestureなど) ModifierとGestureDetectorでサポート .gesture()でサポート
マルチプラットフォーム対応 はい (React Nativeでモバイル対応) いいえ (Androidのみ) はい (Apple製品全般)
学習曲線 中程度 中程度 やや高い
コミュニティとエコシステム 非常に大きい 成長中 成長中

ライフサイクル

ライフサイクルイベント React Jetpack Compose SwiftUI
初回マウント時 componentDidMount() (クラスコンポーネント) / useEffect(() => {...}, []) (関数コンポーネント) DisposableEffect { ... } で初回作成時に実行可能 .onAppear { ... }
アンマウント時 componentWillUnmount() (クラスコンポーネント) / useEffect(() => {... return () => {...}}, []) (関数コンポーネント) DisposableEffect { onDispose { ... } } でアンマウント時に実行 .onDisappear { ... }
更新時 (依存変数の変化) componentDidUpdate() (クラスコンポーネント) / useEffect(() => {...}, [dependencies]) (関数コンポーネント) LaunchedEffect(key) { ... } で特定の依存変数が変化した際に実行 特定のイベントに対応する必要あり
副作用の処理 useEffect() SideEffect { ... } または LaunchedEffect { ... } @State, @Binding, @ObservedObject の変更に応じて動作
非同期処理 useEffect(() => { async function ... }, []) (async/await) LaunchedEffect でサポート (Coroutine) Task { ... } で非同期処理を実行
再レンダリングのトリガー useState, useReducer で状態変更 remember { mutableStateOf(...) } による状態管理 @State, @Binding, @ObservedObject による状態管理
クリーンアップ処理 useEffect(() => {... return () => {...}}, []) でクリーンアップ処理 DisposableEffect { onDispose { ... } } でクリーンアップ処理 .onDisappear { ... } でクリーンアップ処理

データバインディング

機能/特徴 React Jetpack Compose SwiftUI
状態管理 (ローカル) useState remember { mutableStateOf(...) } @State
プロパティ変更による再描画 useState で状態が変わると再描画 mutableStateOf により状態が変わると再描画 @State プロパティが変更されると再描画
親から子へのデータバインディング Props を使用 ModifierComposable パラメータで渡す @Binding を使用して親の状態を共有
状態の監視と更新 (外部依存) useEffect または Context API を使用 StateFlowLiveDatacollectAsState で観測 @ObservedObject@Published を使用
クラスベースの状態管理 クラスコンポーネントで setState を使用 ViewModel クラスと LiveData / StateFlow ObservableObject を使ったクラスで管理
状態の初期化と保持 useState または useReducer を使用 rememberSaveable を使用 @StateObject を使用
グローバルなデータの共有 Context API を使用 CompositionLocal でデータを共有 @EnvironmentObject でデータを共有
UIの更新トリガー useState または setState による更新 MutableState の値変更に基づく プロパティラッパー (@State, @Binding 等) の値変更に基づく
外部APIデータのバインディング useEffect で非同期処理とバインディング LaunchedEffectStateFlow を活用 async/await で非同期処理 + @State にバインド
カスタムイベントハンドリング イベントハンドラ (onClick, onChange など) ModifierLaunchedEffect を使用 .onAppear, .onDisappear などを使用

比較の概要

ローカル状態管理:

ReactではuseStateを使って状態を管理し、Jetpack ComposeではrememberとmutableStateOfを使用、SwiftUIでは@Stateを使ってローカルの状態を管理します。

親子間のデータバインディング:

Reactではpropsを使って親から子にデータを渡し、Jetpack ComposeではパラメータやModifierを使用、SwiftUIでは@Bindingを使って親から子に状態をバインドします。

状態の監視と更新:

ReactではuseEffectやContext APIで状態の監視と更新を行い、Jetpack ComposeではStateFlowやLiveDataを観測し、SwiftUIでは@ObservedObjectと@Publishedを使います。

グローバルデータ共有:

ReactではContext APIを使用してグローバルなデータを共有し、Jetpack ComposeではCompositionLocal、SwiftUIでは@EnvironmentObjectを使います。

外部APIデータのバインディング:

ReactではuseEffectを使って非同期処理とデータバインディングを行い、Jetpack ComposeではLaunchedEffectやStateFlow、SwiftUIではasync/awaitと@Stateを使います。

画面遷移

特徴/フレームワーク React Jetpack Compose SwiftUI
画面遷移のライブラリ react-router-dom (主にWeb向け) NavHost, Composable 間の遷移 NavigationViewNavigationLink
遷移の宣言的な実装 <Link> 要素で実装 NavControllerNavHostを使用 NavigationLink を使用
スタックベースの遷移管理 React Router の useHistoryuseNavigate NavHost でスタックベースの遷移管理 自動的にスタックベース
パラメータの受け渡し URL パラメータ (useParams)を利用 NavControllernavigate にデータ渡す NavigationLink(destination:) で直接渡す
戻る操作 (Back Navigation) useHistory フックを利用 popBackStack()で戻る遷移を実装 NavigationView で自動管理
アニメーションのサポート アニメーションはカスタム実装 AnimatedVisibility, Transition でカスタマイズ matchedGeometryEffect でアニメーション可能
画面遷移後のデータ受け取り URLクエリや状態管理 (Context APIなど) resultBack や Shared ViewModel を使用 @State@Bindingを使用
遷移ガード useEffect とルートガード popBackStack で条件付き遷移可能 onAppear, onDisappear でガード
モーダル遷移 react-modal などのライブラリを利用 DialogBottomSheet を使用 sheet(isPresented:) を使用
多階層の遷移管理 React Router の入れ子ルートで実現 複数のNavHostをネスト可能 NavigationLink をネスト可能

React:

react-router-domを使った宣言的なルーティングが一般的で、Webアプリ向けに最適化されています。useHistoryやuseNavigateでプログラム的に画面遷移を管理し、Linkを使った遷移が基本です。
画面遷移のアニメーションやモーダル表示は、カスタム実装や外部ライブラリに依存することが多いです。

Jetpack Compose:

Androidアプリでの画面遷移は、NavHostとNavControllerを使います。スタックベースのナビゲーション管理ができ、popBackStackで戻り操作を実装できます。
アニメーションや遷移後のデータ受け渡しに関しては、Jetpack Compose専用のコンポーネント(AnimatedVisibilityやSharedViewModel)を利用します。

SwiftUI:

NavigationViewとNavigationLinkを使った宣言的な画面遷移が可能で、簡潔なコードでスタックベースの遷移が自動的に管理されます。
モーダル遷移はsheet(isPresented:)を使って実装でき、画面遷移後のデータ受け渡しには@Stateや@Bindingなどが使われます。

Discussion