So I am working on a view where I want to load state from an EnvironmentObject which acts something like a database.
I would like to achieve something like this:
class MyDB: ObservableObject {
func getName(_ id: RecordID) -> String { ... }
func getChildren(_ id: RecordID) -> [RecordID] { ... }
var didUpdate: PassthroughSubject...
}
struct TreeView: View {
let id: RecordID
@EnvironmentObject var db: DB
@State var name: String
@State var children: [RecordID]
func loadState() {
self.name = db.getName(id)
self.children = db. getChildren(id)
}
var body: some View {
Text(self.name)
List(self.children) { child in
TreeView(id: child)
}
.onReceive(self.db.didUpdate) { _ in
self.loadState()
}
}
}
So basically I would like to just pass the id of the node in the tree view to the child view, and then load the state from this environment object with the loadState
function before the view is displayed.
Is there any way to achieve this? For instance, is there some kind of lifecycle function I could implement which will be called after the environment is bound?
Or for example can I implement loadState inside a custom init?
What would be the idiomatic way to handle this?
CodePudding user response:
I have provided an explanation here if you want to check it out.
You will need to pass your MyDB
instance using .environmentObject(myDBInstance)
on a parent view, so all children views can read from the environment through @EnvironmentObject
.
CodePudding user response:
Try using a different approach, such as the following code,
where children
and name
are published var of MyDB
, and
the functions just load the data into those.
// for testing
struct RecordID: Identifiable {
let id = UUID().uuidString
var thing: String = ""
}
class MyDB: ObservableObject {
@Published var didUpdate: Bool = false
@Published var children: [RecordID] = []
@Published var name: String = ""
func getName(_ id: RecordID) {
// ...
name = "xxx" // whatever
}
func getChildren(_ id: RecordID) {
// ...
children = [RecordID(), RecordID()] // whatever
}
}
struct TreeView: View {
@EnvironmentObject var db: MyDB
@State var id: RecordID
var body: some View {
Text(db.name)
List(db.children) { child in
// TreeView(id: child) // <-- here recursive call, use OutlineGroup instead
Text("\(child.id)")
}
.onReceive(db.$didUpdate) { _ in
loadState()
}
}
func loadState() {
db.getName(id)
db.getChildren(id)
}
}
struct ContentView: View {
@StateObject var myDB = MyDB()
let recId = RecordID()
var body: some View {
TreeView(id: recId).environmentObject(myDB)
}
}