繁体   English   中英

Firebase 删除后 Firestore 不更新 UI SwiftUI

[英]Firebase Firestore doesn't update UI after deletion SwiftUI

我正在尝试通过 SwiftUI 从我的 Firestore 数据库中删除 object 并且数据删除成功。 但是它不会在我的用户界面中更新,除非我手动重新加载它。

现在,我正在使用@Environment(\.presentationMode) var presentation在删除完成后关闭视图。

这是我的 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)
            }
        }
        
    }
}

这是 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来自@State var data: [FirebaseData] = []

这里有几个问题:

  1. 通常,在执行异步工作时,您可能希望在ObservableObject中执行它们,而不是在View本身中执行——我已将代码移至视图 model 中。

  2. 您的 model 不应该是一个ObservableObject它应该只是一个结构。 ObservableObject上使用@State无论如何都不会做任何事情——在使用ObservableObject时使用@Published

  3. 您正在使用一次获取数据的getDocument ,这就是您的 UI 未更新的原因。 如果您希望 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()
            }
        }
    }
}

我会做更多的重构,例如:

  1. 确保你没有使用! 强制解包的任何地方——这可能会导致崩溃
  2. 存储文档 ID,这样您就不会在deleteData中执行其他查询

但是,这应该让你现在开始。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM