You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求基于新ReducerProtocol的Swift Composable Architecture最简共享状态实现示例

用ReducerProtocol实现TCA共享状态的最简示例

核心逻辑

TCA的共享状态不需要额外依赖ObservedObject注入,核心是将共享数据放在顶层全局状态中,通过Reducer的组合(Scope/pullback)让子Feature能访问或修改共享状态。以下是完整的最简实现:


1. 定义全局状态与动作

import ComposableArchitecture

// 共享的用户模型(所有Feature依赖的数据)
struct User: Equatable {
  var name: String
  var darkModeEnabled: Bool
}

// 全局状态:包含共享数据 + 各个子Feature的本地状态
struct AppState: Equatable {
  var user: User
  var profile: ProfileFeature.State
  var settings: SettingsFeature.State
}

// 全局动作:包含子Feature动作 + 修改共享状态的动作
enum AppAction: Equatable {
  case profile(ProfileFeature.Action)
  case settings(SettingsFeature.Action)
  case updateUserName(String)
}

2. 实现子Feature的Reducer

个人资料Feature(修改用户名)

struct ProfileFeature: ReducerProtocol {
  // 子Feature无本地状态,用空结构体占位
  struct State: Equatable {}
  
  enum Action: Equatable {
    case nameChanged(String)
  }
  
  func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
    switch action {
    case .nameChanged(let newName):
      // 发送全局动作,通知顶层Reducer修改共享状态
      return .send(AppAction.updateUserName(newName))
    }
  }
}

设置Feature(切换暗黑模式)

struct SettingsFeature: ReducerProtocol {
  struct State: Equatable {}
  
  enum Action: Equatable {
    case darkModeToggled(Bool)
  }
  
  func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
    // 这里不需要额外逻辑,顶层Reducer会处理该动作并修改共享状态
    return .none
  }
}

3. 顶层Reducer组合与共享状态处理

struct AppReducer: ReducerProtocol {
  var body: some ReducerProtocol<AppState, AppAction> {
    // 将ProfileFeature与全局状态/动作关联
    Scope(state: \.profile, action: /AppAction.profile) {
      ProfileFeature()
    }
    
    // 处理全局动作,修改共享状态
    Reduce { state, action in
      switch action {
      case .settings(.darkModeToggled(let isEnabled)):
        state.user.darkModeEnabled = isEnabled
        return .none
        
      case .updateUserName(let newName):
        state.user.name = newName
        return .none
        
      default:
        return .none
      }
    }
  }
}

4. SwiftUI视图实现

import SwiftUI

// 个人资料视图:读取并修改共享用户名
struct ProfileView: View {
  let store: StoreOf<ProfileFeature>
  
  var body: some View {
    WithViewStore(store) { viewStore in
      TextField("用户名", text: viewStore.binding(
        get: { _ in store.environment.user.name },
        send: ProfileFeature.Action.nameChanged
      ))
      .padding()
    }
  }
}

// 设置视图:读取并修改共享暗黑模式状态
struct SettingsView: View {
  let store: StoreOf<SettingsFeature>
  
  var body: some View {
    WithViewStore(store) { viewStore in
      Toggle("暗黑模式", isOn: viewStore.binding(
        get: { _ in store.environment.user.darkModeEnabled },
        send: SettingsFeature.Action.darkModeToggled
      ))
      .padding()
    }
  }
}

// 主视图:持有全局Store,分发到子视图
struct MainView: View {
  let store: StoreOf<AppReducer>
  
  var body: some View {
    TabView {
      ProfileView(store: store.scope(state: \.profile, action: AppAction.profile))
        .tabItem { Label("个人资料", systemImage: "person") }
      
      SettingsView(store: store.scope(state: \.settings, action: AppAction.settings))
        .tabItem { Label("设置", systemImage: "gear") }
    }
  }
}

// 应用入口
@main
struct SharedStateDemoApp: App {
  static let store = Store(
    initialState: AppState(
      user: User(name: "默认用户", darkModeEnabled: false),
      profile: ProfileFeature.State(),
      settings: SettingsFeature.State()
    ),
    reducer: AppReducer()
  )
  
  var body: some Scene {
    WindowGroup {
      MainView(store: SharedStateDemoApp.store)
    }
  }
}

关键要点

  • 共享状态中心化:所有共享数据放在顶层AppState,避免分散管理。
  • Reducer组合:通过Scope将子Feature的Reducer绑定到全局状态/动作,子Feature可以发送全局动作触发共享状态修改。
  • 视图访问:子视图通过scope从全局Store派生局部Store,通过绑定直接读取/修改共享状态。

内容的提问来源于stack exchange,提问作者Small Talk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 07:05:26