I have data that needs to be requested from backend and then presented as graph.
Im trying to use new async+await and wonder what is the best patter/practice would be.
var body: some View {
VStack {
ZStack {
AreaGraphView( dataPoints: modelData.todayTimeline())
}
}
}
ModelData snippet
@Observable final class ModelData {
// ...
func todayTimeline() async -> [DataPoint] {
// some async work
}
// ....
}
One of options I consider do call to modelData.todayTimeline() in onAppear. It would mean I need to pass dummy or empty data to AreaGraphView.
Any other options?
There is a task modifier that allows you to call an async task. It will be bound to the view's lifetime and cancelled if the view gets discarded.
PS.: Unfortunately this isn't the right platform to ask SwiftUI questions.
sveinhal
(Svein Halvor Halvorsen)
3
Maybe something like so:
enum LoadingState<T> {
case loading
case failed(Error)
case loaded(T)
}
struct LoadingView<Value, Content: View>: View {
let operation: () async throws → Void
@ViewBuilder var content: (Value) -> Content
@State private var loadingState = LoadingState<Value>.loading
var body: some View {
Group {
switch loadingState {
case .loading:
ProgressView()
case .failed(let error):
Text("Failed with error: \(error)")
case .loaded(let value):
content(value)
}
}.task {
do {
loadingState = .loading
let result = try await operation()
loadingState = .loaded(result)
} catch {
loadingState = .failed(error)
}
}
}
}
And then your view could be wrapped like so:
var body: some View {
LoadingView(operation: model.todayTimeline) { timeline in
AreaGraphView(dataPoints: timeline)
}
}
2 Likes