如何从 SwiftUI 中的 EnvironmentObject 加载状态?

发布于 2025-01-09 17:49:46 字数 954 浏览 1 评论 0原文

所以我正在研究一个视图,我想从一个类似于数据库的环境对象加载状态。

我想实现这样的目标:

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()
        }
    }

}

所以基本上我只想将树视图中节点的 id 传递给子视图,然后使用 loadState 从该环境对象加载状态显示视图之前的函数。

有什么办法可以实现这一点吗?例如,我是否可以实现某种生命周期函数,该函数将在环境绑定后调用?

或者例如我可以在自定义 init 中实现 loadState 吗?

处理这个问题的惯用方法是什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

双马尾 2025-01-16 17:49:46

我在此处提供了解释如果你想查看一下。

您需要在父视图上使用 .environmentObject(myDBInstance) 传递 MyDB 实例,以便所有子视图都可以通过 @EnvironmentObject 从环境中读取代码>.

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.

盛夏尉蓝 2025-01-16 17:49:46

尝试使用不同的方法,例如下面的代码,
其中 childrennameMyDB 的已发布变量,并且
这些函数只是将数据加载到其中。

// 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)
    }
}

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)
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文