'SwiftUI Navigation popping back when modifying list binding property in a pushed view

When I update a binding property from an array in a pushed view 2+ layers down, the navigation pops back instantly after a change to the property.

Xcode 13.3 beta, iOS 15.

I created a simple demo and code is below.

Shopping Lists List Edit List section Edit
ShoppingListsView ShoppingListEditView ShoppingListEditsectionView

Updating the list title (one view deep) is fine, navigation stack stays same, and changes are published if I return. But when adjusting a section title (two deep) the navigation pops back as soon as I make a single change to the property.

I have a feeling I'm missing basic fundamentals here, and I have a feeling it must be related to the lists id? but I'm struggling to figure it out or work around it.

GIF

Example

Code:

Models:

struct ShoppingList {
    let id: String = UUID().uuidString
    var title: String
    var sections: [ShoppingListSection]
}

struct ShoppingListSection {
    let id: String = UUID().uuidString
    var title: String
}

View Model:

final class ShoppingListsViewModel: ObservableObject {
    @Published var shoppingLists: [ShoppingList] = [
        .init(
            title: "Shopping List 01",
            sections: [
                .init(title: "Fresh food")
            ]
        )
    ]
}

Content View:

struct ContentView: View {
    var body: some View {
        NavigationView {
            ShoppingListsView()
        }
    }
}

ShoppingListsView

struct ShoppingListsView: View {
    @StateObject private var viewModel = ShoppingListsViewModel()

    var body: some View {
        List($viewModel.shoppingLists, id: \.id) { $shoppingList in
            NavigationLink(destination: ShoppingListEditView(shoppingList: $shoppingList)) {
                Text(shoppingList.title)
            }
        }
        .navigationBarTitle("Shopping Lists")
    }
}

ShoppingListEditView

struct ShoppingListEditView: View {
    @Binding var shoppingList: ShoppingList

    var body: some View {
        Form {
            Section(header: Text("Title")) {
                TextField("Title", text: $shoppingList.title)
            }
            Section(header: Text("Sections")) {
                List($shoppingList.sections, id: \.id) { $section in
                    NavigationLink(destination: ShoppingListSectionEditView(section: $section)) {
                        Text(section.title)
                    }
                }
            }
        }
        .navigationBarTitle("Edit list")
    }
}

ShoppingListSectionEditView

struct ShoppingListSectionEditView: View {
    @Binding var section: ShoppingListSection

    var body: some View {
        Form {
            Section(header: Text("Title")) {
                TextField("title", text: $section.title)
            }
        }
        .navigationBarTitle("Edit section")
    }
}



Solution 1:[1]

try this, works for me:

struct ContentView: View {
    var body: some View {
        NavigationView {
            ShoppingListsView()
        }.navigationViewStyle(.stack)  // <--- here
    }
}

Solution 2:[2]

Try to make you object confirm to Identifiable and return value which unique and stable, for your case is ShoppingList.

Detail view seems will pop when object id changed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 workingdog support Ukraine
Solution 2 Nobel