Skip to content

Commit 2baca64

Browse files
committed
Adding documentation for the new onStoreDidLoad methods
1 parent 9a2408b commit 2baca64

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

Sources/Boutique/Documentation.docc/Articles/Using Stores.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,59 @@ func getItems() async -> [Item] {
114114

115115
The synchronous initializer is a sensible default, but if your app's needs dictate displaying data only once you've loaded all of the necessary items the asynchronous initializers are there to help.
116116

117+
## Observing Store Loading State
118+
119+
You can manually observe the loading state of a ``Store`` as we do in `getItems()` above, but Boutique also provides a ``onStoreDidLoad`` function to observe the loading state of a ``Store`` in SwiftUI.
120+
121+
```swift
122+
struct ContentView: View {
123+
@Stored var items: [Item]
124+
@State var itemsHaveLoaded = false
125+
126+
var body: some View {
127+
VStack {
128+
AlwaysVisibleBanner()
129+
130+
if self.itemsHaveLoaded {
131+
if self.items.isEmpty {
132+
EmptyStateView()
133+
} else {
134+
ItemsView(items: self.items)
135+
}
136+
} else {
137+
LoadingStateView()
138+
}
139+
}
140+
.onStoreDidLoad(
141+
self.$items,
142+
update: $itemsHaveLoaded,
143+
onError: { error in
144+
log.error("Failed to load items", error)
145+
}
146+
)
147+
}
148+
}
149+
```
150+
151+
This allows for a clean separation of Views to display across three different states:
152+
- When the Store has finished loading and has items
153+
- When the Store has finished loading and has no items
154+
- When the Store is loading (and implicitly has no items)
155+
156+
You can also choose to use the closure-oriented variant of ``onStoreDidLoad`` to perform any additional logic when the ``Store`` has finished loading. Patterns like MVVM choose to isolate this logic ViewModel, and you can still choose to do that, but exposing this method on a View provides more flexibility to work with your preferred architecture. In the example below we will filter the items in a ``Store`` based on some criteria, to display only the relevant items in our View.
157+
158+
```swift
159+
.onStoreDidLoad(
160+
self.$items,
161+
onLoad: {
162+
self.items = self.filteredItems(self.items)
163+
},
164+
onError: { error in
165+
log.error("Failed to load items", error)
166+
}
167+
)
168+
```
169+
117170
## Further Exploration, @Stored And More
118171

119172
Building an app using the ``Store`` can be really powerful because it leans into SwiftUI's state-driven architecture, while providing you with offline-first capabilities, realtime updates across your app, with almost no additional code required.

Sources/Boutique/Store+Observation.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ import SwiftUI
22

33
public extension View {
44
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
5+
/// Observes whether a ``Store`` has finished loading it's items.
6+
///
7+
/// - Parameters:
8+
/// - store: The ``Store`` whose loading is being observed.
9+
/// - onLoad: The closure to call when the ``Store`` has finished loading.
10+
/// - onError: The closure to call if an error occurs and the ``Store`` is not loaded.
511
func onStoreDidLoad<StorableItem: Codable & Sendable>(_ store: Store<StorableItem>, onLoad: @escaping () -> Void, onError: ((Error) -> Void)? = nil) -> some View {
612
self.task({
713
do {
@@ -14,6 +20,12 @@ public extension View {
1420
}
1521

1622
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
23+
/// Observes whether a ``Store`` has finished loading it's items.
24+
///
25+
/// - Parameters:
26+
/// - store: The ``Store`` whose loading is being observed.
27+
/// - update: A binding to that will be updated when the ``Store`` has finished loading.
28+
/// - onError: The closure to call if an error occurs and the ``Store`` is not loaded.
1729
func onStoreDidLoad<StorableItem: Codable & Sendable>(_ store: Store<StorableItem>, update hasLoadedState: Binding<Bool>, onError: ((Error) -> Void)? = nil) -> some View {
1830
self.task({
1931
do {

0 commit comments

Comments
 (0)