ViewStore - mbrandonw/swift-composable-architecture GitHub Wiki
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)
}
ObservableObject
Initializes a view store from a store.
public init(_ store: Store<State, Action>, removeDuplicates isDuplicate: @escaping (State, State) -> Bool)
- 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.
A publisher of state.
let publisher: StorePublisher<State>
var viewCancellable: AnyCancellable?
The current state.
var state: State
let _send: (Action) -> Void
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.
- action: - action: An action.
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 Binding
s
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) }
)
)
- 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.
A binding.
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 Binding
s
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)) }
- 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.
A binding.
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 Binding
s
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) }
)
)
- localStateToViewAction: - localStateToViewAction: A function that transforms the binding's value into an action that can be sent to the store.
A binding.
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 Binding
s
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)) }
- action: - action: The action to send when the binding is written to.
A binding.