🙄
TCAにおけるBindingActionとViewActionを利用したActionの整理
なぜBindingActionとViewActionが必要なのか
TCAのReducerでActionを追加していくと、Actionがかなり多くなってしまい処理がわかりにくくなってしまうことがあると思います。
TCAではこれらのActionを整理するBindingActionとViewActionなどの方法があるので、紹介していきたいと思います
1. BindingActionとは何か
BindingActionはSwiftUIの双方向バインディング(@Binding
)をTCAの単方向データフローに統合するためのメカニズムです。これにより、TextField、Toggle、Sliderなどの双方向バインディングを必要とするSwiftUIコンポーネントをTCAと簡単に連携できます。
実際のユースケース
サンプルコードでは、新しいタスクのタイトル入力(newTodoTitle
)とフィルタートグル(filterCompleted
)にBindingAction
を使用しています:
// State内での宣言
var newTodoTitle: String = ""
var filterCompleted: Bool = false
// Actionの定義部分
enum Action: ViewAction, BindableAction, Sendable {
case binding(BindingAction<State>)
// 他のアクション...
}
// Reducerへの組み込み
var body: some ReducerOf<Self> {
BindingReducer()
Reduce { state, action in
switch action {
case .binding:
return .none
// 他のケース...
}
}
}
ビューでの使用方法
ビュー側では、$store
バインディングを使って直接状態に接続します:
TextField("新しいタスク", text: $store.newTodoTitle)
.textFieldStyle(RoundedBorderTextFieldStyle())
Toggle("完了済みのみ表示", isOn: $store.filterCompleted)
.tint(.green)
BindingActionの実装
- Actionに
BindableAction
プロトコルを適用:
enum Action: BindableAction {
case binding(BindingAction<State>)
// 他のケース...
}
- Reducerに
BindingReducer
を追加:
var body: some ReducerOf<Self> {
BindingReducer()
Reduce { state, action in
// 他のアクション処理...
}
}
- storeを
@Bindable
として宣言:
@Bindable var store: StoreOf<TodoFeature>
- Viewで双方向バインディングを使用:
TextField("新しいタスク", text: $store.newTodoTitle)
2. ViewActionとは何か
ViewActionは、Viewから発生するアクションを整理し、Actionの列挙型を簡潔に保つためのパターンです。これにより、Actionの一覧の中でViewからのActionを明示的に表現することができ、Actionの一覧がわかりやすくなります
実際のユースケース
サンプルコードでは、Viewから発生するすべてのActionをView
列挙型内に整理しています:
enum Action: ViewAction, BindableAction, Sendable {
case binding(BindingAction<State>)
case view(View)
enum View: Equatable {
case onAppear
case addTodoButtonTapped
case todoCheckboxToggled(id: Todo.ID)
case deleteTodoButtonTapped(id: Todo.ID)
}
}
ビューでの使用方法
Viewからは@ViewAction
マクロを使用して、簡潔にアクションを送信できます:
@ViewAction(for: TodoFeature.self)
struct TodoView: View {
@Bindable var store: StoreOf<TodoFeature>
var body: some View {
Button(action: {
send(.addTodoButtonTapped)
}) {
Image(systemName: "plus.circle.fill")
.font(.title2)
.foregroundColor(.blue)
}
// 他のビュー要素...
}
}
実装手順
ViewActionの実装
- フィーチャーのActionに
ViewAction
プロトコルを適用:
enum Action: ViewAction {
case view(View)
enum View {
}
}
- ビューに
@ViewAction
マクロを適用:
@ViewAction(for: TodoFeature.self)
struct TodoView: View {
}
-
send()
関数を使ってアクションを送信:
Button(action: {
send(.addTodoButtonTapped)
}) {
}
まとめ
BindingActionとViewActionによるActionの整理について紹介しました
サンプルコードも合わせて確認してください
TCAのドキュメントでも記載されているのでこちらも合わせて確認してください
Discussion