🍎

TCAでTabViewの状態管理をする

2025/02/08に公開

Note(ノート)

TCAを使用してTavViewの状態管理をやってみた。通常は@Stateを使用して状態管理をおこなう。

https://youtube.com/shorts/sWJE9y6LA8M

SwiftUIでプロジェクトを作成して、SPMでTCAを追加する。
https://github.com/pointfreeco/swift-composable-architecture

タブは2個作成する。HomeViewとSettingsViewを作成する。

ホーム画面(仮)

HomeView.swift
import SwiftUI

struct HomeView: View {
    var body: some View {
        Text("ホーム画面")
    }
}

#Preview {
    HomeView()
}

設定画面(仮)

SettingsView.swift
import SwiftUI

struct SettingsView: View {
    var body: some View {
        Text("設定画面")
    }
}

#Preview {
    SettingsView()
}

TabFeatureを作成。このファイルで状態管理をするReducerActionを作成する。enumを使ってhomesettingsというデータ型を定義する。タップすると画面が更新されてページの表示が切り替わるようになっております。

import ComposableArchitecture

enum Tab {
    case home
    case settings
}

@Reducer
struct TabFeature {
    struct State: Equatable {
        var selectedTab: Tab = .home
    }
    
    enum Action {
        case tabSelected(Tab)
    }
    
    var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case let .tabSelected(tab):
                state.selectedTab = tab
                return .none
            }
        }
    }
} 

MainTabViewを作成する。このページがTabViewの画面になる。

MainTabView.swift
import SwiftUI
import ComposableArchitecture

struct MainTabView: View {
    let store: StoreOf<TabFeature>
    
    var body: some View {
        WithViewStore(store, observe: { $0 }) { viewStore in
            TabView(
                selection: viewStore.binding(
                    get: \.selectedTab,
                    send: TabFeature.Action.tabSelected
                )
            ) {
                // ホーム画面
                HomeView()
                    .tabItem {
                        Image(systemName: "house.fill")
                        Text("ホーム")
                    }
                    .tag(Tab.home)
                
                // 設定画面
                SettingsView()
                    .tabItem {
                        Image(systemName: "gear")
                        Text("設定")
                    }
                    .tag(Tab.settings)
            }
        }
    }
}

// プレビュー用
#Preview {
    MainTabView(
        store: Store(
            initialState: TabFeature.State()
        ) {
            TabFeature()
        }
    )
} 

ContentViewを編集してStoreを定義してアプリケーション全体で使用できるように設定する。

ContentView.swift
import SwiftUI
import ComposableArchitecture

struct ContentView: View {
    let store: StoreOf<TabFeature> = Store(
        initialState: TabFeature.State()
    ) {
        TabFeature()
    }
    
    var body: some View {
        MainTabView(store: store)
    }
}

#Preview {
    ContentView()
} 

Que(きっかけ)

SwiftUIの状態管理は、TCA一択と聞いた?
本当かな。ViewModelとSwiftUIは相性が悪いらしくTCAを使用して、Reduxアーキテクチャと同じかな。ストアー・アクションなどで状態管理をするのが相性が良いらしい。

Summary(要約)

このコードは、SwiftUIアプリケーションでタブベースのナビゲーションを実装するための、The Composable Architecture (TCA)を使用した基本的な機能を定義しています。

主なポイントは:

  1. Tab 列挙型で、homeとsettingsの2つのタブを定義しています。
  2. TabFeatureは以下の要素を含むReducerです:
    • State構造体:現在選択されているタブをselectedTabプロパティとして管理
    • Action列挙型:タブ選択時のtabSelectedアクションを定義
    • bodyプロパティ:状態更新のロジックを実装
  3. シンプルな状態管理を実現しており、タブが選択されると対応する状態が更新される仕組みになっています。
    このコードは、TCAの基本的なパターンに従って実装されており、アプリケーションのタブ切り替え機能の土台となる部分を担っています。

Discussion