简体   繁体   English

SwiftUI 不会在嵌套 NavigationLink 目标中使用 ObservedObject 更新 UI

[英]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) }
    }
}

DeferView is taken from this my post. DeferView取自我的这篇文章。

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

相关问题 SwiftUI - 尽管使用了@Published 和@ObservedObject,但视图不会更新 - SwiftUI - View doesn't update despite using @Published and @ObservedObject SwiftUI @ObservedObject &amp; @StateObject 不会更新 UI,一些 UI 不会随机显示 - SwiftUI @ObservedObject & @StateObject won't Update UI, some UI not showing up randomly 如果父对象有更新,则 ObservedObject 无法处理 NavigationLink 的目标 - ObservedObject not working on NavigationLink's destination if there are updates on parent SwiftUI 自定义视图的 ViewBuilder 不会在子类 ObservedObject 更新上重新渲染/更新 - SwiftUI custom View's ViewBuilder doesn't re-render/update on subclassed ObservedObject update NavigationLink、isActive 在 SwiftUI 中不起作用 - NavigationLink, isActive doesn´t work in SwiftUI SwiftUI NavigationLink 不会使用 onReceive 方法触发 - SwiftUI NavigationLink doesn't trigger with onReceive method 在 SwiftUI 中有条件地更改 NavigationLink 目标 - Change NavigationLink destination conditionally in SwiftUI SwiftUI - 嵌套导航链接 - SwiftUI - Nested NavigationLink iOS15 - 如果新视图的出现更新 ObservedObject,则第一个 NavigationLink 不起作用 - iOS15 - First NavigationLink doesn't work if onAppear of new view updates ObservedObject SwiftUI:NavigationView/NavigationLink:启动并推送目的地? - SwiftUI: NavigationView/NavigationLink: launch with destination pushed?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM