SwiftUI 不会更新第二个 NavigationLink 目的地

Mic*_*sky 5 swiftui swiftui-navigationlink

我有一个列表,其中包含推送视图的行。该视图有另一个列表,它推送另一个视图。原来的List,第一个推送的List会随着数据的变化而更新。但是,推送时最后一个视图不会更新。当我向后滑动视图不再更新时,即使它曾经更新过。

HomeView > UserView > ItemView

User 和 Item 是可识别的结构。我试过让它们 Hashable 并使用id: \.self,但这似乎也不起作用。

class App: ObservableObject {
    @Published var users = [User]()
}

struct HomeView {

    @EnvironmentObject var app: App

    var body {
        List {
            Section {
                ForEach(app.users) { user in
                    NavigationLink(destination: UserView(user: user)) {
                        Text(user.name)
                    }
                }
            }
        }
    }

}

// Updates fine when `app.users` updates
// Stops updating after going back from ItemView
struct UserView {

    let user: User

    var body {
        List {
            Section {
                ForEach(user.items) { item in
                    NavigationLink(destination: ItemView(user: user, item: item)) {
                        Text(item.name)
                    }
                }
            }
        }
    }

}

/// Does not update when app.users updates
struct ItemView {

    let user: User
    let item: Item

    var body {
        List {
            Section {
                ForEach(item.details) { detail in
                    Text(detail)
                }
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

Mic*_*sky 1

经过长时间的搜索,我想出了一些我在互联网其他地方还没有看到的东西。我正在使用父视图中的 @State 初始化我的视图,并使用 onReceive 更新它。此外,onReceive/onAppear 检查该项目是否仍然有效,并在需要时弹出视图。进行 init 来设置状态并将其设为私有可能更正确。

主要原因是删除导致崩溃。这是我为测试更改和删除源而制作的完整示例。

struct Item: Identifiable {
    var id: String
    var name: String
    var accounts: [Account]
}

struct Account: Identifiable {
    var id: String
    var name: String
}

class App: ObservableObject {
    @Published var items: [Item] = [
        Item(id: "a", name: "A", accounts: [
            Account(id: "1", name: "one"),
            Account(id: "2", name: "two"),
            Account(id: "3", name: "three")
        ])
    ]
}

struct RootView: View {
    var body: some View {
        NavigationView {
            ContentView().environmentObject(App())
        }
    }
}

struct ContentView: View {

    @EnvironmentObject var app: App

    var body: some View {
        List {
            ForEach(app.items) { item in
                NavigationLink(destination: ItemView(item: item)) {
                    Text("\(item.id) - \(item.name)")
                }
            }
            Button(action: { self.app.items[0].name = "XXX" }) {
                Text("Change Item Name")
            }
            Button(action: { self.app.items = [] }) {
                Text("Clear")
            }
        }
    }

}

struct ItemView: View {

    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject var app: App

    @State var item: Item

    var body: some View {
        List {
            Text("\(item.id) - \(item.name)")
            ForEach(item.accounts) { account in
                NavigationLink(destination: AccountView(item: self.item, account: account)) {
                    Text("\(account.id) - \(account.name)")
                }
            }
            Button(action: { self.app.items[0].name = "XXX" }) {
                Text("Change Item Name")
            }
            Button(action: { self.app.items[0].accounts[0].name = "AAA" }) {
                Text("Change Account Name")
            }
            Button(action: { self.app.items = [] }) {
                Text("Clear")
            }
        }
        .onReceive(app.$items) { items in
            guard let item = items.first(where: { $0.id == self.item.id }) else {
                self.presentationMode.wrappedValue.dismiss()
                return
            }
            self.item = item
        }
        .onAppear {
            if !self.app.items.contains(where: { $0.id == self.item.id }) {
                self.presentationMode.wrappedValue.dismiss()
            }
        }
    }

}

struct AccountView: View {

    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject var app: App

    @State var item: Item
    @State var account: Account

    var body: some View {
        List {
            Text("\(item.id) - \(item.name)")
            Text("\(account.id) - \(account.name)")
            Button(action: { self.app.items[0].name = "XXX" }) {
                Text("Change Item Name")
            }
            Button(action: { self.app.items[0].accounts[0].name = "AAA" }) {
                Text("Change Account Name")
            }
            Button(action: { self.app.items = [] }) {
                Text("Clear")
            }
        }
        .onReceive(app.$items) { items in
            guard
                let item = items.first(where: { $0.id == self.item.id }),
                let account = item.accounts.first(where: { $0.id == self.account.id })
            else {
                self.presentationMode.wrappedValue.dismiss()
                return
            }
            self.item = item
            self.account = account
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么不喜欢?他们能解释一下吗 (3认同)