History
Loading...
Loading...
September 14, 2025
.refreshable modifier on any scrollable view for native pull-to-refresh behavior. The closure automatically receives a RefreshAction that completes when your async operation finishes, giving users proper visual feedback without manual state management.Always handle errors within refreshable actions and provide user feedback. The refreshable modifier automatically manages the loading state, but error states need explicit handling to maintain good user experience.
struct ContentView: View {
@State private var items: [String] = []
@State private var errorMessage: String?
var body: some View {
NavigationView {
List(items, id: \.self) { item in
Text(item)
}
.refreshable {
await refreshData()
}
.alert("Error", isPresented: .constant(errorMessage != nil)) {
Button("OK") { errorMessage = nil }
} message: {
Text(errorMessage ?? "")
}
.navigationTitle("Items")
}
}
private func refreshData() async {
do {
// Simulate network call
try await Task.sleep(nanoseconds: 1_000_000_000)
items = await fetchItems()
errorMessage = nil
} catch {
errorMessage = "Failed to refresh: \(error.localizedDescription)"
}
}
private func fetchItems() async -> [String] {
// Your actual data fetching logic
return ["Item 1", "Item 2", "Item 3"]
}
}Users expect immediate feedback when refresh operations fail. Without proper error handling, failed refreshes appear successful since the pull-to-refresh indicator dismisses normally, leaving users confused about why their content didn't update.