Skip to content

Instantly share code, notes, and snippets.

@natpenguin
Last active May 9, 2022 00:50
Show Gist options
  • Save natpenguin/528cb1769b08391f6349f2647a61f109 to your computer and use it in GitHub Desktop.
Save natpenguin/528cb1769b08391f6349f2647a61f109 to your computer and use it in GitHub Desktop.
A propertyWrapper for supporting declarative data fetching on SwiftUI with Firebase Cloud Firestore
@propertyWrapper
struct CollectionListener<Document: Codable>: DynamicProperty {
final class FirestoreDocumentsListener {
typealias OnUpdate = ([Document]) -> Void
private var onUpdate: OnUpdate?
private var listenerRegistration: ListenerRegistration?
func listen(path: String, firestore: Firestore, onUpdate: OnUpdate? = nil) {
self.onUpdate = onUpdate
guard listenerRegistration == nil else { return }
listenerRegistration = firestore.collection(path)
.addSnapshotListener({ [weak self] snapshot, error in
guard let self = self else { return }
if let _ = error {
self.onUpdate?([])
} else if let snapshot = snapshot {
do {
let data = try snapshot.documents.compactMap {
try $0.data(as: Document.self)
}
self.onUpdate?(data)
} catch {
self.onUpdate?([])
}
} else {
self.onUpdate?([])
}
})
}
}
private let listener: FirestoreDocumentsListener = .init()
@State var wrappedValue: [Document] = []
@Environment(\.firestore) var firestore
private let path: String
func update() {
listener.listen(
path: path,
firestore: firestore
) { documents in
self.wrappedValue = documents
}
}
init(path: String) {
self.path = path
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment