Replies: 2 comments
-
Tested it with Edit 1 Edit 2 extension ViewStore {
@MainActor
func send(_ action: ViewAction, suspendWhile predicate: @escaping (ViewState) -> Bool) async {
self.send(action)
await Task { @MainActor in
_ = await self.publisher.values.first(where: { !predicate($0) })
}.value
}
} |
Beta Was this translation helpful? Give feedback.
-
This seems to be a bug in SwiftUI. I can reproduce the same problem in vanilla SwiftUI if I use an observed object rather than class Model: ObservableObject {
@Published var isLoading = false
@Published var response: String?
func load() async {
self.isLoading = true
defer { self.isLoading = false }
try? await Task.sleep(for: .seconds(2))
self.response = UUID().uuidString
}
}
struct ContentViewVanilla: View {
@ObservedObject var model = Model()
var body: some View {
TabView {
NavigationView {
ScrollView {
Text(self.model.response ?? "Pull To Refresh…")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.foregroundColor(self.model.response == nil ? .secondary : .primary)
}
.refreshable {
await self.model.load()
}
.navigationTitle(Text("Vanilla Scroll View"))
}
.tabItem {
Label("Scroll View", systemImage: "scroll")
}
NavigationView {
List {
Text(self.model.response ?? "Pull To Refresh…")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.foregroundColor(self.model.response == nil ? .secondary : .primary)
}
.refreshable {
await self.model.load()
}
.navigationTitle(Text("Vanilla List"))
}
.tabItem {
Label("List", systemImage: "list.bullet.clipboard")
}
}
}
} It seems to have something to do with updating a published property while the pull-to-refresh work is being done. If you get rid of the If you get rid of the Since this doesn't seem to be a bug in the library I am going to convert it to a discussion. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Description
Attaching a
.refreshable
modifier onScrollView
and using the suggestedViewStore.send(_:while:)
action in the body produces a flakey behaviour.Using the code example provided in the documentation of the function causes the following behaviour:
1 - User pulls to refresh: Loading stops immediately. No action received after side effect completes.
2 - User pulls to refresh: Loading waits for side effect to complete. Result action received after side effect completes.
3 - User pulls to refresh: Loading stops immediately. No action received after side effect completes.
4 - User pulls to refresh: Loading waits for side effect to complete. Result action received after side effect completes.
and so on.
This behaviour is not present when using a
List
.The bug occurs on both latest released version
0.55.0
and on themain
branch.Vanilla SwiftUI seems to be working fine with both ScrollView and List.
Attached videos and test project:
RefreshableList.mov
RefreshableScrollView.mov
TCARefreshable.zip
Checklist
main
branch of this package.Expected behavior
1 out of 2 times, pull to refresh on ScrollView with TCA doesn't wait for loading to complete and the reducer doesn't receive action that is supposed to be fed back.
Actual behavior
Every time you do pull to refresh, the loading indicator persists while the side effect is ongoing, dismisses when it completes, and the reducer receives the result action from the side effect.
Steps to reproduce
ViewStore.send(_:while:)
function.The Composable Architecture version information
0.55.0 and main
Destination operating system
iOS 16.4
Xcode version information
14.3.1
Swift Compiler version information
Beta Was this translation helpful? Give feedback.
All reactions