[英]Firebase Firestore doesn't update UI after deletion SwiftUI
I'm trying to delete an object from my Firestore database through SwiftUI and the data deletes successfully.我正在尝试通过 SwiftUI 从我的 Firestore 数据库中删除 object 并且数据删除成功。 However it doesn't update in my UI, unless I reload it manually.
但是它不会在我的用户界面中更新,除非我手动重新加载它。
Right now, I'm using @Environment(\.presentationMode) var presentation
to dismiss the view after deletion completion.现在,我正在使用
@Environment(\.presentationMode) var presentation
在删除完成后关闭视图。
Here's my Firebase code:这是我的 Firebase 代码:
func deleteData(category: String,completion: @escaping (success) -> Void){
db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").getDocument{(snapshot, error) in
guard let snapshot = snapshot, error == nil else {
return
}
let documentID = snapshot.data()!["date"] as! String
db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID).document("\(category)").delete(){ err in
if let err = err {
print("Error removing document: \(err)")
completion(false)
} else {
print("Document successfully removed!")
completion(true)
}
}
}
}
And here's the SwiftUI code:这是 SwiftUI 代码:
@Environment(\.presentationMode) var presentation
var body: some View {
ForEach(self.data){item in
HStack{
Text(item.category)
Spacer()
Button(action: {
deleteData(category: item.category!){
(success) -> Void in
if success {
print("deleted successfully")
self.presentation.wrappedValue.dismiss()
}
}
}){
Text("Delete")
}
}
.onAppear{
fetchData()
}
}
}
class FirebaseData: ObservableObject {
@State var id: String?
@State var category: String
@State var password: String
init(id: String?, password: String, category: String) {
self.id = id
self.password = password
self.category = category
}
}
self.data
comes from @State var data: [FirebaseData] = []
. self.data
来自@State var data: [FirebaseData] = []
。
There are a few problems here:这里有几个问题:
In general, when doing asynchronous work, you probably want to do them in an ObservableObject
, and not in the View
itself -- I've moved the code into a view model.通常,在执行异步工作时,您可能希望在
ObservableObject
中执行它们,而不是在View
本身中执行——我已将代码移至视图 model 中。
Your model shouldn't be an ObservableObject
-- it should just be a struct.您的 model 不应该是一个
ObservableObject
它应该只是一个结构。 Using @State
on an ObservableObject
doesn't do anything anyways -- use @Published
values when using ObservableObject
在
ObservableObject
上使用@State
无论如何都不会做任何事情——在使用ObservableObject
时使用@Published
值
You're using getDocument
which gets the data once , which is why your UI isn't updating.您正在使用一次获取数据的
getDocument
,这就是您的 UI 未更新的原因。 If you want the UI to update, use snapshot listeners: https://firebase.google.com/docs/firestore/query-data/listen如果您希望 UI 更新,请使用快照监听器: https://firebase.google.com/docs/firestore/query-data/listen
struct FirebaseData {
var id: String?
var category: String
var password: String
}
class ViewModel : ObservableObject {
@Published var data : [FirebaseData] = []
private let db = Firestore.firestore()
private var listener : ListenerRegistration?
func fetchData(){
db.collection("passwords").document("\(Auth.auth().currentUser!.uid)")
.getDocument{(snapshot, error) in
guard let snapshot = snapshot, error == nil else {
return
}
let documentID = snapshot.data()!["date"] as! String
self.listener = self.db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID)
.addSnapshotListener(){ (querySnapshot, err) in //<-- Here
if let err = err {
print("Error getting documents: \(err)")
} else {
self.data = (querySnapshot?.documents ?? []).map {
FirebaseData(id: $0.documentID,
category: $0.data()["category"] as? String ?? "",
password: $0.data()["password"] as? String ?? "")
}
}
}
}
}
func deleteData(category: String,completion: @escaping (success) -> Void){
db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").getDocument{(snapshot, error) in
guard let snapshot = snapshot, error == nil else {
return
}
let documentID = snapshot.data()!["date"] as! String
self.db.collection("passwords").document("\(Auth.auth().currentUser!.uid)").collection(documentID).document("\(category)").delete(){ err in
if let err = err {
print("Error removing document: \(err)")
completion(false)
} else {
print("Document successfully removed!")
completion(true)
}
}
}
}
}
struct ContentView: View {
@Environment(\.presentationMode) var presentation
@StateObject private var viewModel = ViewModel()
var body: some View {
NavigationView{
ForEach(viewModel.data, id: \.self.id) { item in
HStack{
Text(item.category)
Spacer()
Button(action: {
viewModel.deleteData(category: item.category){
(success) -> Void in
if success {
print("deleted successfully")
}
}
}){
Text("Delete")
}
}
}
.onAppear{
viewModel.fetchData()
}
}
}
}
There's some more refactoring I'd do, such as:我会做更多的重构,例如:
!
!
anywhere to force unwrap -- this can cause crashesdeleteData
deleteData
中执行其他查询But, this should get you started for now.但是,这应该让你现在开始。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.