Thanks for this post @Appeloper. My team and me are reading through it and it's making us think a lot about our current practices and the architecture we are using.
There is something that is make me struggle a lot. With this approach your view have freedom to use one or more "Stores" if they need to, this is an important difference regarding MVVM where any view would have her own ViewModel, is this correct?
Then you could end up having something like this:
class AllChannelStore: ObservableObject {
@Published var channels: [Channel] = []
@Published var isLoading: Bool = false
var loadError: Error? = nil
func load() async {
isLoading = true
do {
channels = try await Channel.channels
} catch {
loadError = error
}
isLoading = false
}
}
class FavoriteChannelStore: ObservableObject {
@Published var channels: [Channel] = []
@Published var isLoading: Bool = false
var loadError: Error? = nil
func load() async {
isLoading = true
do {
channels = try await Channel.favoriteChannels
} catch {
loadError = error
}
isLoading = false
}
}
struct HomeChannelList: View {
@StateObject private var allChannelStore = AllChannelStore()
@StateObject private var favoriteChannelStore = FavoriteChannelStore()
var body: some View {
if ????isLoading???? {
ProgressView()
} else if ????isError???? {
ErrorView()
} else {
ContentView()
}
.task {
await allChannelStore.channels
await favoriteChannelStore.channels
}
}
}
Here we have one view that uses two different stores as source of true since it has to show the Favorite channels, but also All channels.
In this scenario how would you control the state the view is in (loading, success, failure, etc)?
My ideas are:
We could still have the state in each ObservableObject separately, but then we would need to add a bunch of logic after await favoriteChannelStore.channels to see if any of the two stores has given an error, or maybe (depending on the business logic) it could be okey to render only part of the view if one of the two hasn't failed.
Move everything to the view, so that she can control her own state. But I'm afraid that doing so you would end up with views that would controller their state and some other views that would have it controlled by the ObservableObject and I don't like this kind of inconsistencies.
Add another Store on top of Favorite channels and All channels store that would control this... which sounds a lot like going back to ViewModels
I have the feeling I'm missing something really basic here, and some insights on it would be really appreciated