Wait Up A Second…
The highlight of this release a new async initializer for a Boutique Store
, thanks to the contribution of @rl-pavel. This initializer solves two problems.
- Previously when an app was starting up you would have to wait for a
Store
to finish loading before moving onto your next task, ostensibly acting as a blocking procedure. TheStore
was fast so it was not very noticeable from a performance perspective, but depending on the state-driven interface you were constructing and how big yourStore
was, it could be noticeable. - The main problem this caused was not being able to tell whether the items in your
Store
still hadn't loaded, or if they had loaded with zero items. I call this the empty state problem, where you would see your empty state screen displayed for a split second, and then your items would load into place. This was a suboptimal experience, but is now a thing of the past.
You shouldn't notice any changes when using the Store's initializer, but you will now have this fancy method that shows you if the store has finished loading.
await store.itemsHaveLoaded()
What this allows you to do is to drive a SwiftUI/UIKit/AppKit view based on the Store's state. A simplified example looks like this.
struct ItemListView: View {
@State private var itemsHaveLoaded = false
var body: some View {
VStack {
AlwaysVisibleBanner()
if self.itemsHaveLoaded {
if self.items.isEmpty {
EmptyStateView()
} else {
ItemView(items: self.items)
}
} else {
LoadingStateView()
}
}
.task({
try await self.itemsController.items.itemsHaveLoaded()
self.itemsHaveLoaded = true
})
}
}
This is a a really readable solution to a tricky problem, so once again, thank you Pavel. 👏🏻
Breaking Changes
StoredValue.binding
is now computed property rather than aStoredValue.binding()
function.- I've added back the
Store.Operation.add
functions which allowed for chained operations, they were accidentally marked as deprecated, oops.