Skip to content

v0.3.0

Compare
Choose a tag to compare
@gordonbrander gordonbrander released this 27 Jan 13:20
· 14 commits to main since this release
332458e

What's Changed

Full Changelog: 0.2.0...v0.3.0

Breaking: removed ViewStore in favor of forward

ViewStore has been removed in favor of a new child component patter that is closer to vanilla SwiftUI.

The key problem with the ViewStore approach was that the getter for the store value dynamically got the value, meaning that for stores of list items, the state of the store always had to be an Optional. SwiftUI avoids this problem by passing down bare properties to list items. See #19 for more details.

Child components are now handled the way you handle child components in vanilla SwiftUI, with bare state and a send method.

struct ChildView: View {
    var state: ChildModel
    var send: (ChildAction) -> Void

    var body: some View {
        VStack {
            Text("Count \(state.count)")
            Button(
                "Increment",
                action: {
                    store.send(ChildAction.increment)
                }
            )
        }
    }
}

To integrate the child view, we can use Address.forward to create a tagged send function for the child that will translate all child actions into parent actions.

struct ContentView: View {
    @StateObject private var store = Store(
        state: AppModel(),
        environment: AppEnvironment()
    )

    var body: some View {
        ChildView(
            state: store.state.child,
            send: Address.forward(
                send: store.send,
                tag: AppChildCursor.tag
            )
        )
    }
}

Breaking: Binding signature change

Bindings have changed from Binding(store:get:tag) to Binding(get:send:tag:). Typical use looks like this:

TextView(
    "Placeholder",
    Binding(
        get: { store.state.text },
        send: store.send,
        tag: Action.setText
    )
)

The old signature relied on ViewStore's conformance to StoreProtocol. The new signature just requires a getter closure and a send function, so is less opinionated about the specifics of this library.

Actions publisher

Store now exposes Store.actions, a publisher which publishes all actions sent to send. This is useful for logging actions. It is also useful for integrating ObservableStore with other SwiftUI features, or for wiring together stores in codebases that use multiple stores.

Now both state and actions are published (state already has a publisher through $state), so it is easy to wired up store events to other SwiftUI features using onReceive.

Logging example:

.onReceive(store.actions) { action in
    // do logging
}