ViewStore - mbrandonw/swift-composable-architecture GitHub Wiki

ViewStore

A ViewStore is an object that can observe state changes and send actions. They are most commonly used in views, such as SwiftUI views, UIView or UIViewController, but they can be used anywhere it makes sense to observe state and send actions.

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

In SwiftUI applications, a ViewStore is accessed most commonly using the WithViewStore view. It can be initialized with a store and a closure that is handed a view store and must return a view to be rendered:

var body: some View {
  WithViewStore(self.store) { viewStore in
    VStack {
      Text("Current count: \(viewStore.count)")
      Button("Increment") { viewStore.send(.incrementButtonTapped) }
    }
  }
}

In UIKit applications a ViewStore can be created from a Store and then subscribed to for state updates:

let store: Store<State, Action>
let viewStore: ViewStore<State, Action>

init(store: Store<State, Action>) {
  self.store = store
  self.viewStore = ViewStore(store)
}

func viewDidLoad() {
  super.viewDidLoad()

  self.viewStore.publisher.count
    .sink { [weak self] in self?.countLabel.text = $0 }
    .store(in: &self.cancellables)
}

@objc func incrementButtonTapped() {
  self.viewStore.send(.incrementButtonTapped)
}

Inheritance

ObservableObject

Initializers

init(_:removeDuplicates:)

Initializes a view store from a store.

public init(_ store: Store<State, Action>, removeDuplicates isDuplicate: @escaping (State, State) -> Bool)

Parameters

  • store: - store: A store.
  • isDuplicate: - isDuplicate: A function to determine when two State values are equal. When values are equal, repeat view computations are removed.

Properties

publisher

A publisher of state.

let publisher: StorePublisher<State>

viewCancellable

var viewCancellable: AnyCancellable?

state

The current state.

var state: State

_send

let _send: (Action) -> Void

Methods

send(_:)

Sends an action to the store.

public func send(_ action: Action)

ViewStore is not thread safe and you should only send actions to it from the main thread. If you are wanting to send actions on background threads due to the fact that the reducer is performing computationally expensive work, then a better way to handle this is to wrap that work in an Effect that is performed on a background thread so that the result can be fed back into the store.

Parameters

  • action: - action: An action.

binding(get:send:)

Derives a binding from the store that prevents direct writes to state and instead sends actions to the store.

public func binding<LocalState>(get: @escaping (State) -> LocalState, send localStateToViewAction: @escaping (LocalState) -> Action) -> Binding<LocalState>

The method is useful for dealing with SwiftUI components that work with two-way Bindings since the Store does not allow directly writing its state; it only allows reading state and sending actions.

For example, a text field binding can be created like this:

struct State { var name = "" }
enum Action { case nameChanged(String) }

TextField(
  "Enter name",
  text: viewStore.binding(
    get: { $0.name },
    send: { Action.nameChanged($0) }
  )
)

Parameters

  • get: - get: A function to get the state for the binding from the view store's full state.
  • localStateToViewAction: - localStateToViewAction: A function that transforms the binding's value into an action that can be sent to the store.

Returns

A binding.

binding(get:send:)

Derives a binding from the store that prevents direct writes to state and instead sends actions to the store.

public func binding<LocalState>(get: @escaping (State) -> LocalState, send action: Action) -> Binding<LocalState>

The method is useful for dealing with SwiftUI components that work with two-way Bindings since the Store does not allow directly writing its state; it only allows reading state and sending actions.

For example, an alert binding can be dealt with like this:

struct State { var alert: String? }
enum Action { case alertDismissed }

.alert(
  item: self.store.binding(
    get: { $0.alert },
    send: .alertDismissed
  )
) { alert in Alert(title: Text(alert.message)) }

Parameters

  • get: - get: A function to get the state for the binding from the view store's full state.
  • action: - action: The action to send when the binding is written to.

Returns

A binding.

binding(send:)

Derives a binding from the store that prevents direct writes to state and instead sends actions to the store.

public func binding(send localStateToViewAction: @escaping (State) -> Action) -> Binding<State>

The method is useful for dealing with SwiftUI components that work with two-way Bindings since the Store does not allow directly writing its state; it only allows reading state and sending actions.

For example, a text field binding can be created like this:

struct State { var name = "" }
enum Action { case nameChanged(String) }

TextField(
  "Enter name",
  text: viewStore.binding(
    send: { Action.nameChanged($0) }
  )
)

Parameters

  • localStateToViewAction: - localStateToViewAction: A function that transforms the binding's value into an action that can be sent to the store.

Returns

A binding.

binding(send:)

Derives a binding from the store that prevents direct writes to state and instead sends actions to the store.

public func binding(send action: Action) -> Binding<State>

The method is useful for dealing with SwiftUI components that work with two-way Bindings since the Store does not allow directly writing its state; it only allows reading state and sending actions.

For example, an alert binding can be dealt with like this:

struct State { var alert: String? }
enum Action { case alertDismissed }

.alert(
  item: self.store.binding(
    send: .alertDismissed
  )
) { alert in Alert(title: Text(alert.message)) }

Parameters

  • action: - action: The action to send when the binding is written to.

Returns

A binding.

⚠️ **GitHub.com Fallback** ⚠️