Stop using .onAppear() for async work in SwiftUI
Task {
await viewModel.loadData()
}
}
The problem? SwiftUI doesn't manage that Task for you.
If the view disappears, your network call keeps running in the background. Even worse, onAppear can fire multiple times in certain navigation scenarios. 🐛
There's a better way: .task()
.task {
await viewModel.loadData()
}
That's it. SwiftUI automatically cancels the task when the view disappears. No memory leaks, no unnecessary work, no manual cleanup.
But it gets even better with .task(id:)
Let's say you're building a user profile screen. When the userID changes, you need to reload the data:
.task(id: userID) {
await viewModel.loadUser(userID)
}
Every time userID changes, SwiftUI cancels the previous task and starts a new one automatically. No need for .onChange(), no manual task cancellation logic.
Quick comparison:
❌ .onAppear - Fires on appear, no automatic cancellation, can fire multiple times
✅ .task - Fires on appear, auto-cancels on disappear
✅ .task(id:) - Also re-runs when the id changes, canceling the previous task
This is one of those small changes that makes your SwiftUI code cleaner and more reliable.
Comments
Post a Comment