State、Action、Reducer
機能を、Stateに対する純粋なReducerとしてモデル化します。
「State、Action、Reducer」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全4レッスンが含まれています。
Composable Architectureとは
Composable Architecture(TCA)は、一貫性があり、テスト可能な構造でSwiftアプリを構築するためのライブラリです。中心となるのは3つの要素です。機能のデータを表すState、発生し得るすべてのイベントを表すAction、そしてアクションに応じてStateを変化させるReducerです。
この一方向のデータフローにより、機能の動作が予測しやすく、テストも簡単になります。
import ComposableArchitecture
// State holds data, Action describes events,
// a Reducer turns (state, action) into the next state.@Reducerマクロ
機能は、@Reducerマクロでアノテーションを付けた型として定義します。このマクロによって補助コードが生成され、State、Action、Reducerの body を1つのまとまりとして一緒に宣言できます。
慣例として、型には機能にちなんだ名前を付けます。たとえば CounterFeature のようにします。
import ComposableArchitecture
@Reducer
struct CounterFeature {
// State, Action, and body go here
}Stateの定義
State は通常、機能に必要なすべてのデータを保持するstructです。@ObservableState を付けると、SwiftUIが変更を正確に監視し、影響を受ける部分だけを再レンダリングできるようになります。
Stateは最小限に保ち、派生値は計算して求めることで、信頼できる唯一の情報源を維持します。
import ComposableArchitecture
@Reducer
struct CounterFeature {
@ObservableState
struct State: Equatable {
var count = 0
}
}Actionの定義
Action は、ユーザーのタップ、レスポンス、タイマーのティックなど、機能が処理できるすべてのイベントを列挙するenumです。各caseはStateを直接変更する命令ではなく、発生した出来事を表します。
分かりやすいアクション名にすると、機能の動作がコード自体で説明されます。
import ComposableArchitecture
@Reducer
struct CounterFeature {
@ObservableState
struct State: Equatable { var count = 0 }
enum Action {
case incrementTapped
case decrementTapped
}
}Reducerのbody
Reducerのロジックは、some ReducerOf<Self> を返す計算プロパティ body に記述します。その中で Reduce を使い、変更可能な state と受け取った action を受け取るクロージャを定義します。
アクションをswitch文で分岐し、それに応じてStateを変更します。
import ComposableArchitecture
@Reducer
struct CounterFeature {
@ObservableState
struct State: Equatable { var count = 0 }
enum Action { case incrementTapped, decrementTapped }
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .incrementTapped:
state.count += 1
return .none
case .decrementTapped:
state.count -= 1
return .none
}
}
}
}Effectの返却
Reducerの各分岐では、Effect を返す必要があります。.none を返すと、Stateの変更後に実行する非同期処理がないことを表します。
ネットワーク呼び出しなどの副作用が必要な場合は、その処理を実行するEffectを返します。Effectについては後のレッスンで詳しく学びます。
import ComposableArchitecture
// Every reducer branch returns an Effect.
// No side effect needed? Return .none.
// Need async work? Return an effect describing it.
Reduce { state, action in
state.count += 1
return .none
}Stateの変更を一元化する
TCAの基本ルールは、Stateを変更できるのはReducerだけであり、変更はアクションへの応答としてのみ行うということです。ViewがStateを直接変更することはありません。Viewはアクションを送信します。
このように変更処理を1か所に集約することで、データフローを追跡しやすく、テストもしやすくなります。
import ComposableArchitecture
// Views send actions; the reducer mutates state.
// store.send(.incrementTapped) -> state.count += 1
// No direct state mutation outside the reducer.Stateでユーザー入力をモデル化する
フォームのような機能では、編集可能なフィールドを State に保持し、変更用のアクションを追加します。プロパティにバインディングを付けると、SwiftUIのコントロールから型安全にアクションを通して更新できるようになります。
ここでは、テキストフィールドとトグルを機能のStateで管理します。
import ComposableArchitecture
@Reducer
struct FormFeature {
@ObservableState
struct State: Equatable {
var name = ""
var isSubscribed = false
}
enum Action: BindableAction {
case binding(BindingAction<State>)
}
var body: some ReducerOf<Self> {
BindingReducer()
}
}関連値を持つAction
Actionは、関連値を使ってデータを保持できます。読み込んだアイテムやエラーなど、処理結果をモデル化するときに使います。これにより、Reducerはその値をStateに保存できます。
ここでは、レスポンスアクションが取得した数値を保持します。
import ComposableArchitecture
@Reducer
struct NumberFeature {
@ObservableState
struct State: Equatable { var value = 0 }
enum Action {
case reloadTapped
case responseReceived(Int)
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .reloadTapped:
return .none
case let .responseReceived(value):
state.value = value
return .none
}
}
}
}EquatableなStateが役立つ理由
State を Equatable に準拠させると、TCAはStateが実際に変更されたかどうかを検出できます。これにより、Viewの正確な更新と網羅的なテストが可能になります。小さな要件ですが、大きなメリットがあります。
保存するプロパティがすでに Equatable であれば、多くのState型は追加の処理なしで Equatable に準拠できます。
import ComposableArchitecture
@ObservableState
struct State: Equatable {
var count = 0
var title = ""
}
// Equatable enables change detection and test assertions.完成した機能の構成
完成した機能は、上から順に読むと、マクロ、監視可能なState、アクションenum、Reducerのbodyで構成されています。機能に関するすべての要素が1つの型に収まるため、TCAの機能は組み合わせやすく、レビューもしやすくなります。
この一貫した構成は、アプリ内のすべての機能で繰り返し使われます。
import ComposableArchitecture
@Reducer
struct CounterFeature {
@ObservableState
struct State: Equatable { var count = 0 }
enum Action { case incrementTapped, decrementTapped }
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .incrementTapped: state.count += 1; return .none
case .decrementTapped: state.count -= 1; return .none
}
}
}
}クイックチェック:3つの要素
TCAにおけるState、Action、Reducerの役割を思い出しましょう。
まとめ:State、Action、Reducer
TCAの機能の中心となる要素を学びました。
@Reducerは、すべての要素を1か所に含む機能の型を定義します。- structに
@ObservableStateを付けると、機能のデータを保持し、正確な監視が可能になります。 Actionenumには、関連値を持たせることもできる、すべてのイベントを列挙します。- Reducerの
bodyはReduceを使ってStateを変更し、Effectを返します。副作用が不要な場合は.noneを返します。 - Stateを変更できるのはReducerだけなので、データフローを予測しやすく保てます。
次はStoreを使って、この機能をSwiftUIに接続します。
import ComposableArchitecture
// Recap: @Reducer + State + Action + body(Reduce)
// One type, one source of truth, predictable updates.よくある質問
「State、Action、Reducer」レッスンは無料ですか?
はい。「State、Action、Reducer」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全4レッスンが含まれています。
「State、Action、Reducer」で何を学びますか?
機能を、Stateに対する純粋なReducerとしてモデル化します。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Swift Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「State、Action、Reducer」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSwift Academyレッスンでコードを書いて実行できますか?
はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- State、Action、Reducer
- StoreとSwiftUIの統合
- Effectと依存関係
- 機能の合成とテスト