[英]SwiftUI doesn't update UI with ObservedObject in nested NavigationLink destination
I currently have an app that's fetching data from an API, In the root view (let's call it Home) everything works as expected, in the second view (let's call it User View) everything works as expected but now on the third view (Team View) the ObservedObject
for this view only is not working.我目前有一个从 API 获取数据的应用程序,在根视图(我们称之为 Home)中,一切都按预期工作,在第二个视图(我们称之为用户视图)中,一切都按预期工作,但现在在第三个视图(团队视图)仅用于此视图的ObservedObject
不起作用。
The strangest part is that if the user navigates directly to the Team View, again every thing works as expected.最奇怪的部分是,如果用户直接导航到团队视图,一切都会按预期工作。
Each view has it's own ObservedObject
has the data being loaded belongs only to that view每个视图都有自己的ObservedObject
加载的数据仅属于该视图
The navigation between each view is made by the NavigationLink
每个视图之间的导航由NavigationLink
完成
Heres an exemple of how I'm doing the loading and navigation.这是我如何进行加载和导航的示例。
struct HomeView: View {
@ObservedObject var viewModel = HomeViewModel()
var body: some View {
VStack {
NavigationLink(destination: UserView(userId: viewModel.userId))
NavigationLink(destination: TeamView(teamId: viewModel.teamId))
}
}
}
struct TeamView: View {
@ObservedObject var viewModel = TeamViewModel()
@State var teamId: String = ""
var body: some View {
Text(viewModel.name)
.onAppear() { viewModel.loadData(id: teamId) }
}
}
struct UserView: View {
@ObservedObject var viewModel = UserViewModel()
@State var userId: String = ""
var body: some View {
VStack {
Text(viewModel.name)
NavigationLink(destination: TeamView(teamId: viewModel.teamId))
}
.onAppear() { viewModel.loadData(id: userId) }
}
}
From the example you can see that the function to load the data is in the view model and is loaded when the view appears从示例中可以看到加载数据的 function 在视图 model 中,并在视图出现时加载
Everything works just fine but when I reach the 3rd level in the stack the data does not get updated in the view.一切正常,但是当我到达堆栈中的第 3 级时,视图中的数据不会更新。 I thought It might be the thread but I'm using DispatchQueue.main.async
when the fetch is complete.我认为这可能是线程,但是当提取完成时我正在使用DispatchQueue.main.async
。
All necessary variables on the Model are marked as @Published
Model 上的所有必要变量都标记为@Published
In sum the following flows work总之,以下流程有效
HomeView -> TeamView
HomeView -> UserView
But this one on the last view it does load the data but it does not update the view但是这个在最后一个视图上它确实加载了数据但它不更新视图
HomeView -> UserView -> TeamView
I replicated your code behaviour and the issue is due to fast navigation.我复制了您的代码行为,问题是由于快速导航。 Here is what's going on这是发生了什么
if you would do如果你愿意
HomeView [tap] -> UserView -> [wait for user loaded] -> TeamView // no issue
but you do但你做了
HomeView [tap] -> UserView [tap] -> TeamView // got defect
The defect is because UserView
is updated in background when the data got loaded, so body
rebuilt, so link is recreated, so TeamView
is reconstructed, but .onAppear
is not called, because such kind of view is already on screen.缺陷是因为UserView
在加载数据时在后台更新,因此重新构建了body
,因此重新创建了链接,因此重新构建了TeamView
,但是没有调用.onAppear
,因为这种视图已经在屏幕上。
(I'm not sure if this is SwiftUI bug, because there is logic in such behaviour). (我不确定这是否是 SwiftUI 错误,因为这种行为是有逻辑的)。
So here is a solution for this case.因此,这是针对这种情况的解决方案。 Tested with Xcode 11.5b.使用 Xcode 11.5b 测试。
struct TeamView: View {
@ObservedObject var viewModel = TeamViewModel()
var teamId: String // << state is not needed
init(teamId: String) {
self.teamId = teamId
viewModel.loadData(id: teamId) // initiate load here !!
}
var body: some View {
Text(viewModel.name)
}
}
struct UserView: View {
@ObservedObject var viewModel = UserViewModel()
@State var userId: String = ""
var body: some View {
VStack {
Text(viewModel.name)
// used DeferView to avoid in-advance constructions
NavigationLink(destination: DeferView { TeamView(teamId: viewModel.teamId) })
}
.onAppear() { viewModel.loadData(id: userId) }
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.