The Composable Architecture

一、State

1
2
3
struct CounterState: Equatable {
var count = 0
}

二、Action

1
2
3
4
enum CounterAction: Equatable {
case decrementButtonTapped
case incrementButtonTapped
}

三、Environment

1
struct CounterEnvironment {}

四、Reducer

1
2


  • 处理事件以及状态的变化
  • 返回Effect

1. combine

把多个reducer组合成一个

  • reducers的顺序会影响结果

2. pullback

利用local state, action and environment构造全局的reducer

  • 参数:

    • toLocalState: 可写的keyPath,能够从GlobalState中取出LocalState
    • toLocalAction: casePath,能将LocalActioin extract/embed 到GlobalAction.
    • toLocalEnvironment: 函数,能将 GlobalEnvironment转为 LocalEnvironment.
  • 使用:

    • // Global domain that holds a local domain:
      struct AppState { var settings: SettingsState, /* rest of state */ }
      enum AppAction { case settings(SettingsAction), /* other actions */ }
      struct AppEnvironment { var settings: SettingsEnvironment, /* rest of dependencies */ }
      
      // A reducer that works on the local domain:
      let settingsReducer = Reducer<SettingsState, SettingsAction, SettingsEnvironment> { ... }
      
      // Pullback the settings reducer so that it works on all of the app domain:
      let appReducer: Reducer<AppState, AppAction, AppEnvironment> = .combine(
          settingsReducer.pullback(
              state: \.settings,
              action: /AppAction.settings,
              environment: { $0.settings }
          ),
      
          /* other reducers */
      )
      <!--4-->
      

3. optional

将reducer中 state映射为State?

五、Store

1
Store<State, Action>
  • 存储了state和action

1. WithViewStore

可以接受Store,并将其转换为@ObservedObject ViewStore<State, Action>

1
2
3
4
5
6
7
8
9
10
var body: some View {
WithViewStore(self.store) { viewStore in
HStack {
Button("−") { viewStore.send(.decrementButtonTapped) }
Text("\(viewStore.count)")
.font(Font.body.monospacedDigit())
Button("+") { viewStore.send(.incrementButtonTapped) }
}
}
}

1.1 ViewStore

1
2
@dynamicMemberLookup
public final class ViewStore<State, Action>: ObservableObject

viewStore可以访问到state的属性

原理:将ViewStore声明为dynamicMemberLookup,并实现他的subscript<LocalState>(dynamicMember keyPath: KeyPath<State, LocalState>) -> LocalState方法,即可访问到ViewStore中未定义的成员(若访问到成员不存在,就会返回subscript方法的执行结果)

send

viewStore可以发送一个action到store,store中的reducer会接受并处理

ViewStore不是线程安全的,因此send方法一定要在主线程调用

binding

  • 初始化时传入get函数(获取state)和set函数(发送action)
  • 有关联值的枚举,如果只写关联值以外的部分,可以当做函数来使用:比如 viewStore.binding(get: { $0.text }, send: BindingBasicsAction.textChange)BindingBasicsAction.textChange 就是一个输入为 String, 输出为 BindingBasicsAction 实例的函数

2. scope

通过全局的Store获取local Store中的state或者action

  • 参数
    • toLocalState:修改local state
    • fromLocalAction:接收local action
1
2
3
4
5
6
7
8
9
10
11
12
// Application state made from local states.
struct AppState { var login: LoginState, ... }
struct AppAction { case login(LoginAction), ... }
// A store that runs the entire application.
let store = Store(initialState: AppState(), reducer: appReducer, environment: ())
// Construct a login view by scoping the store to one that works with only login domain.
let loginView = LoginView(
store: store.scope(
state: { $0.login }, //取出AppState中的login
action: { AppAction.login($0) } //用loginAction生成AppAction
)
)

3. IfLetStore

判断当前store中的State是不是可选的

0%