简体   繁体   English

Firebase 删除后 Firestore 不更新 UI SwiftUI

[英]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:这里有几个问题:

  1. 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 中。

  2. 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 ObservableObjectObservableObject上使用@State无论如何都不会做任何事情——在使用ObservableObject时使用@Published

  3. 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:我会做更多的重构,例如:

  1. Make sure you're not using !确保你没有使用! anywhere to force unwrap -- this can cause crashes强制解包的任何地方——这可能会导致崩溃
  2. Store the document ID so that you're not doing another query inside deleteData存储文档 ID,这样您就不会在deleteData中执行其他查询

But, this should get you started for now.但是,这应该让你现在开始。

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

相关问题 firebase/firestore/lite 不适用于 firebase 模拟器? - firebase/firestore/lite doesn't work with firebase emulator? SwiftUI - 在 Firebase 上更新密码 - SwiftUI - Update password on Firebase 一段时间后更新 Firebase Firestore 数据 - Update Firebase Firestore Data After A Certain Amount of Time 在 Firebase 模拟器中一次更新后多次读取 Firestore 文档 - Firestore document is read multiple times after a single update in Firebase emulator 如何在 SwiftUI 中使用 Firebase Auth 登录后检查用户是否已存在于 Firestore 集合中 - How to check if a user already exists in a Firestore collection after signing in with Firebase Auth in SwiftUI 无法使用 firebase firestore 对未安装的组件执行 React state 更新 - Can't perform a React state update on an unmounted component with firebase firestore Facebook 主电子邮件更改后,Firebase 不会更新 Facebook 用户的电子邮件 - Firebase doesn't update email of Facebook user after Facebook primary email changes 用户终止应用程序后,Firestore 调用未完全执行 - Firestore call doesn't execute completely after user terminates the app Firebase docker 容器中的身份验证模拟器 UI 在本地主机上不起作用 - Firebase Authentication Emulator UI in docker container doesn't work on localhost Firebase Function 查询和更新单个 Firestore 文档 - Firebase Function query and update a single Firestore document
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM