0Pricing
Swift Academy · 课时

Store 与 SwiftUI 集成

通过 TCA store 驱动视图。

Store 与 SwiftUI 集成 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

什么是 Store

Store 是一个运行时对象,用于保存功能状态并运行其归约器。SwiftUI 视图会观察 Store 以读取状态,并向它发送操作来触发变化。

Store 是纯归约器逻辑与实时交互界面之间的桥梁。

import ComposableArchitecture
import SwiftUI

// A Store holds State, runs the Reducer,
// and is observed by SwiftUI views.

StoreOf 类型别名

StoreOf<Feature> 是一个便捷别名,表示针对某个功能的状态类型和操作类型进行专门化的 Store。视图通常会将它作为存储属性。

因此,计数器视图会存储一个 StoreOf<CounterFeature>。

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        Text("Count: \(store.count)")
    }
}

创建 Store

您可以使用 Store 初始化器创建 Store,并提供初始状态以及要运行的归约器。通常,您会在应用入口附近只执行一次此操作。

尾随闭包会返回功能的一个实例。

import ComposableArchitecture
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            CounterView(
                store: Store(initialState: CounterFeature.State()) {
                    CounterFeature()
                }
            )
        }
    }
}

直接读取状态

借助现代观察机制,视图可以使用点语法直接从 Store 读取状态,例如 store.count。由于状态是 @ObservableState,SwiftUI 只会重新渲染依赖于已变化值的部分。

对于简单读取,不需要额外的包装器。

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        VStack {
            Text("Count: \(store.count)")
        }
    }
}

发送操作

要改变状态,视图可以通过 store.send(.someAction) 发送操作。Store 会将操作传递给归约器,由归约器修改状态,并可能启动效果。

这里的按钮会发送递增和递减操作。

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        HStack {
            Button("-") { store.send(.decrementTapped) }
            Text("\(store.count)")
            Button("+") { store.send(.incrementTapped) }
        }
    }
}

从 Store 创建绑定

对于需要双向绑定的 SwiftUI 控件,TCA 允许您在状态使用可绑定操作时,从 Store 派生出一个 Binding。控件通过发送绑定操作来更新状态。

这里的 TextField 绑定到一个名称字段。

import ComposableArchitecture
import SwiftUI

struct FormView: View {
    @Bindable var store: StoreOf<FormFeature>
    var body: some View {
        TextField("Name", text: $store.name)
    }
}

旧式 WithViewStore

在观察机制出现之前,视图会使用 WithViewStore 包装界面,以读取状态并获取用于发送操作的 viewStore。您仍会在较旧的代码中看到这种写法。

observe 闭包会选择视图所依赖的状态。

import ComposableArchitecture
import SwiftUI

struct LegacyCounter: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        WithViewStore(store, observe: { $0 }) { viewStore in
            Text("Count: \(viewStore.count)")
        }
    }
}

选择要观察的内容

在旧式写法中,observe 闭包会缩小视图所观察的状态范围,因此只有这些值发生变化时,视图才会重新渲染。观察整个状态最简单;观察状态子集则可以优化大型视图。

现代的 @ObservableState 会自动处理这些工作,但理解 observe 有助于您阅读旧代码。

import ComposableArchitecture
import SwiftUI

// Observe just the count to limit re-renders:
WithViewStore(store, observe: { $0.count }) { viewStore in
    Text("\(viewStore)")
}

发送带载荷的操作

发送带有关联值的操作时,需要提供该值。这是视图转发归约器所需用户输入的方式。

这里,选择一行会发送所选行的标识符。

import ComposableArchitecture
import SwiftUI

struct ListView: View {
    let store: StoreOf<ListFeature>
    var body: some View {
        Button("Pick 42") {
            store.send(.rowSelected(id: 42))
        }
    }
}

为操作添加动画

您可以为发送的操作附加动画,使由此产生的状态变化带有动画效果。请将 animation 参数传递给 send。

这样可以将动画相关逻辑保留在调用位置,同时让状态保持为普通数据。

import ComposableArchitecture
import SwiftUI

Button("Toggle") {
    store.send(.toggleTapped, animation: .default)
}

组装视图

完整的 TCA 视图会持有一个 StoreOf,使用点语法读取状态,并从控件发送操作。其余工作由归约器完成,从而让视图保持精简和声明式。

正是这种分离让 TCA 视图易于阅读和预览。

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        VStack {
            Text("Count: \(store.count)")
            Button("Increment") { store.send(.incrementTapped) }
        }
    }
}

快速检查:驱动界面

请回忆 SwiftUI 视图如何在 TCA 中触发状态变化。

回顾:Store 与 SwiftUI

您已经将一个功能连接到了 SwiftUI:

  • StoreOf<Feature> 保存状态并运行归约器。
  • 您可以使用初始状态和功能归约器创建 Store。
  • 现代观察机制允许您使用点语法读取状态,例如 store.count。
  • 视图通过调用 store.send(.action) 改变状态,也可以选择传入载荷或动画。
  • 旧式的 WithViewStore 及其 observe 闭包会出现在较旧的代码中。

接下来,您将为归约器添加副作用和可注入的依赖。

import ComposableArchitecture
import SwiftUI

// Recap: StoreOf holds state, view reads with dot syntax,
// store.send(.action) drives every change.

常见问题解答

「Store 与 SwiftUI 集成」课时是免费的吗?

是的 — 「Store 与 SwiftUI 集成」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「Store 与 SwiftUI 集成」这节课中我会学到什么?

通过 TCA store 驱动视图。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「Store 与 SwiftUI 集成」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 状态、操作与归约器
  2. Store 与 SwiftUI 集成
  3. 副作用与依赖
  4. 组合和测试功能
← 返回 Swift Academy