ViewModel

@MainActor
@dynamicMemberLookup
public final class ViewModel<State, Event> : ObservableObject where State : Equatable

A view model wraps a store and observes state changes that can be used within a view.

extension RootScreen {
    struct ContentView: View {
        let store: Store
        @StateObject var viewModel: ViewModel<AppState, AppEvent>

        // MARK: Body

        var body: some View {
            VStack(alignment: .center) {
                Text(verbatim: .init(self.viewModel.count))
                    .font(.largeTitle)

                HStack {
                    Button("Decrement") {
                        self.viewModel.send(.decrement)
                    }
                    .buttonStyle(.bordered)

                    Button("Increment") {
                        self.viewModel.send(.increment)
                    }
                    .buttonStyle(.bordered)

                    Button("Delayed increment") {
                        self.viewModel.send(.incrementWithDelay)
                    }
                    .buttonStyle(.bordered)
                }
            }
        }
    }
}
  • The state of the store.

    Declaration

    Swift

    @Published
    public var state: State { get set }

Initialization

  • Create a new view model instance.

    Declaration

    Swift

    public init<Environment>(_ store: Store<State, Event, Environment>)

    Parameters

    store

    The store.

API

  • Send an event to the store.

    Declaration

    Swift

    public func send(_ event: Event)

    Parameters

    event

    The even to send.

  • Returns the resulting state value of a given key path.

    Declaration

    Swift

    public subscript<T>(dynamicMember keyPath: KeyPath<State, T>) -> T { get }

Binding

  • Creates a Binding that prevents direct write access to the state and instead sends an event on set.

    This makes working with SwiftUI components easier.

    For example:

    TextField(
        "Email",
        text: viewStore.binding(
            get: \.email,
            send: { .setEmail($0) }
        )
    )
    

    Declaration

    Swift

    public func binding<ScopedState>(
        value: @escaping (State) -> ScopedState,
        event: @escaping (ScopedState) -> Event
    ) -> Binding<ScopedState> where ScopedState: Equatable

    Parameters

    value

    A function to extract the value from the state.

    event

    A function to build the event that is sent to the store.

    Return Value

    A binding.

  • Creates a Binding that prevents direct write access to the state and instead sends an event on set.

    This makes working with SwiftUI components easier.

    For example:

    SomeView()
        .alert(
            "Error",
            isPresented: self.store.binding(
                value: { $0.loginStatus.isFailed },
                event: .resetLoginState
            ),
            actions: { },
            message: {
                Text(self.store.loginStatus.failedMessage)
            }
        )
    

    Declaration

    Swift

    public func binding<ScopedState>(
        value: @escaping (State) -> ScopedState,
        event: Event
    ) -> Binding<ScopedState> where ScopedState: Equatable

    Parameters

    value

    A function to extract the value from the state.

    event

    An event that is sent to the store.

    Return Value

    A binding.

  • Creates a readonly Binding.

    This makes working with SwiftUI components easier.

    For example:

    .fullScreenCover(
        isPresented: self.viewModel.binding(
            value: { !$0.isLoggedIn }
        ),
        onDismiss: nil,
        content: {
            Text("Logged out")
        }
    )
    

    Declaration

    Swift

    public func binding<ScopedState>(
        value: @escaping (State) -> ScopedState
    ) -> Binding<ScopedState>

    Parameters

    value

    A function to extract the value from the state.

    Return Value

    A readonly binding.