@@ -143,7 +143,7 @@ import SwiftUI
143143 ///
144144 /// Binding actions can also be tested in much the same way regular actions are tested. Rather
145145 /// than send a specific action describing how a binding changed, such as
146- /// `displayNameChanged("Blob")`, you will send a ``Reducer/binding(action:)`` action that
146+ /// `. displayNameChanged("Blob")`, you will send a ``Reducer/binding(action:)`` action that
147147 /// describes which key path is being set to what value, such as `.set(\.$displayName, "Blob")`:
148148 ///
149149 /// ```swift
@@ -242,7 +242,7 @@ import SwiftUI
242242 }
243243 }
244244
245- /// An action type that exposes a `binding` case for the purpose of reducing .
245+ /// An action type that exposes a `binding` case that holds a ``BindingAction`` .
246246 ///
247247 /// Used in conjunction with ``BindableState`` to safely eliminate the boilerplate typically
248248 /// associated with mutating multiple fields in state.
@@ -329,8 +329,8 @@ import SwiftUI
329329 /// Useful in transforming binding actions on view state into binding actions on reducer state
330330 /// when the domain contains ``BindableState`` and ``BindableAction``.
331331 ///
332- /// For example, we can model an app that can bind a number to a stepper and make a network
333- /// request to fetch a number fact with the following domain:
332+ /// For example, we can model an app that can bind an integer count to a stepper and make a
333+ /// network request to fetch a fact about that integer with the following domain:
334334 ///
335335 /// ```swift
336336 /// struct AppState: Equatable {
@@ -368,12 +368,13 @@ import SwiftUI
368368 /// The view may want to limit the state and actions it has access to by introducing a
369369 /// view-specific domain that contains only the state and actions the view needs. Not only will
370370 /// this minimize the number of times a view's `body` is computed, it will prevent the view
371- /// from accessing state or sending actions outside its purview.
371+ /// from accessing state or sending actions outside its purview. We can define it with its own
372+ /// bindable state and bindable action:
372373 ///
373374 /// ```swift
374375 /// extension AppView {
375376 /// struct ViewState: Equatable {
376- /// var count: Int
377+ /// @BindableState var count: Int
377378 /// let fact: String?
378379 /// // no access to any other state on `AppState`, like child domains
379380 /// }
@@ -386,10 +387,10 @@ import SwiftUI
386387 /// }
387388 /// ```
388389 ///
389- /// And in order to transform `BindingAction<ViewState>` into `BindingAction<AppState>`, we
390- /// need a writable key path from `AppState` to `ViewState`, which we can get by defining a
391- /// computed property with a getter and setter, where the setter can communicate any updates to
392- /// bindable view state to the store :
390+ /// In order to transform a `BindingAction<ViewState>` sent from the view domain into a
391+ /// `BindingAction<AppState>`, we need a writable key path from `AppState` to `ViewState`. We
392+ /// can synthesize one by defining a computed property on `AppState` with a getter and a setter.
393+ /// The setter should communicate any mutations to bindable state back to the parent state :
393394 ///
394395 /// ```swift
395396 /// extension AppState {
@@ -400,32 +401,43 @@ import SwiftUI
400401 /// }
401402 /// ```
402403 ///
403- /// Finally, in the view we can use ``Store/scope(state:action:)-9iai9`` to pluck out view
404- /// state, embed view actions, and transform binding actions between domains:
404+ /// With this property defined it is now possible to transform a `BindingAction<ViewState>` into
405+ /// a `BindingAction<AppState>`, which means we can transform a `ViewAction` into an
406+ /// `AppAction`. This is where `pullback` comes into play: we can unwrap the view action's
407+ /// binding action on view state and transform it with `pullback` to work with app state. We can
408+ /// define a helper that performs this transformation, as well as route any other view actions
409+ /// to their reducer equivalents:
405410 ///
406411 /// ```swift
407- /// var body: some View {
408- /// WithViewStore(
409- /// self.store.scope(
410- /// state: { .init(count: $0.count, fact: $0.fact) }
411- /// action: {
412- /// switch $0 {
413- /// case let .binding(action):
414- /// return .binding(action.pullback(\.view)) // transform binding action
415- /// case .factButtonTapped:
416- /// return .factButtonTapped
417- /// }
418- /// }
419- /// )
420- /// ) { viewStore in
421- /// ...
412+ /// extension AppAction {
413+ /// static func view(_ viewAction: AppView.ViewAction) -> Self {
414+ /// switch viewAction {
415+ /// case let .binding(action):
416+ /// // transform view binding actions into app binding actions
417+ /// return .binding(action.pullback(\.view))
418+ ///
419+ /// case let .factButtonTapped
420+ /// // route `ViewAction.factButtonTapped` to `AppAction.factButtonTapped`
421+ /// return .factButtonTapped
422+ /// }
422423 /// }
423424 /// }
424425 /// ```
425426 ///
426- /// This is a lot, though both state and action transformations could be pulled out to their own
427- /// helpers. Importantly, the view has whittled away its domain and can only read state it has
428- /// access to, and send actions it has access to.
427+ /// Finally, in the view we can invoke ``Store/scope(state:action:)-9iai9`` with these domain
428+ /// transformations to leverage the view store's binding helpers:
429+ ///
430+ /// ```swift
431+ /// WithViewStore(
432+ /// self.store.scope(state: \.view, action: AppAction.view)
433+ /// ) { viewStore in
434+ /// Stepper("\(viewStore.count)", viewStore.$count)
435+ /// Button("Get number fact") { viewStore.send(.factButtonTapped) }
436+ /// if let fact = viewStore.fact {
437+ /// Text(fact)
438+ /// }
439+ /// }
440+ /// ```
429441 ///
430442 /// - Parameter keyPath: A key path from a new type of root state to the original root state.
431443 /// - Returns: A binding action over a new type of root state.
0 commit comments