AsyncButton’a Duyulan İhtiyaç
Standart SwiftUI Button eylemleri senkrondur. Asenkron bir işlem yapman gerektiğinde – bir ağ isteği, veritabanı yazımı, StoreKit satın alımı – elle bir Task yönetmek, yükleme durumunu takip etmek, butonu devre dışı bırakmak ve hataları ele almak zorunda kalıyorsun. Bu kalıp kod, uygulamandaki her asenkron butonda tekrarlanıyor.
Tüm bunları tek bir yeniden kullanılabilir view’da saran bir AsyncButton bileşeni oluşturdum.
Basitleştirilmiş Bir Uygulama
İşte temel fikir:
struct AsyncButton<Label: View>: View {
let action: () async throws -> Void
let label: () -> Label
@State private var isRunning = false
@State private var result: Result<Void, Error>?
var body: some View {
Button {
isRunning = true
Task {
do {
try await action()
result = .success(())
} catch {
result = .failure(error)
}
isRunning = false
}
} label: {
HStack(spacing: 8) {
label()
if isRunning {
ProgressView()
}
}
}
.disabled(isRunning)
}
}Buton dahili olarak bir Task oluşturuyor, böylece çağıranlar action closure’ında doğrudan await kullanabiliyor. Task çalışırken, etiketin yanında bir ProgressView görünüyor ve mükerrer gönderileri önlemek için buton devre dışı bırakılıyor. result state’i başarı veya başarısızlık göstergelerini – bir onay işareti, bir renk flaşı veya bir sallama animasyonu – yönlendirebilir.
Kullanım
Kullanımı doğal hissettiriyor:
AsyncButton {
try await viewModel.submitOrder()
} label: {
Text("Place Order")
}Elle state yönetimi yok, çağrı noktasında Task oluşturma yok. HandySwiftUI paketindeki tam implementasyon yapılandırılabilir başarı/başarısızlık animasyonları, özelleştirilebilir ilerleme göstergeleri ve buton stilleri desteği ekliyor. Ama yukarıdaki temel kalıp en yaygın durumu kapsıyor ve kendi projelerine uyarlaması kolay.
