Search code examples
iosswiftswiftuiswiftui-navigationlink

swiftui subview reappear after click the back button and update state data


Very strange behavior.

Click the back button on the subpage (Subview) to return to the main page (ContentView). However, the subpage (Subview) automatically opens again. Why?

import SwiftUI

struct ContentView: View {
    @State var things: [String] = []
    @State var count: Int = 0
    
    var body: some View {
        NavigationView{
            List {
                ForEach(things.indices, id: \.self) { index in
                    Text(things[index])
                }
            }
            .onAppear {
                update()
            }
           
            .navigationTitle("a")
            .toolbar{
                NavigationLink(destination: Subview(count: $count), label: {
                    Text("sub")
                })
            }
        }
        
    }
    
    func update() {
        things = []
        for i in 0...count {
            things.append(String(i))
        }
    }
}

struct Subview: View {
    var count : Binding<Int>

    var body: some View {
        Text("sub")
            .onAppear {
                count.wrappedValue += 1
            }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Pressing back button goes back, but then automatically pushes to new page again

Solution

  • NavigationLink should always be inside a NavigationView. If you put it in the toolbar or some other place, you might run into weird issues.

    Instead, use the init(destination:isActive:label:) initializer. Then set the presentingNextPage property to true when you want to present the next page.

    struct ContentView: View {
        @State var things: [String] = []
        @State var count: Int = 0
        @State var presentingNextPage = false
        
        var body: some View {
            NavigationView {
                
                List {
                    ForEach(things.indices, id: \.self) { index in
                        Text(things[index])
                    }
                    
                    /// placeholder navigation link
                    NavigationLink(destination: Subview(count: $count), isActive: $presentingNextPage) {
                        EmptyView()
                    }
                }
                .onAppear {
                    self.update()
                }
                .navigationTitle("a")
                .toolbar{
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button("sub") {
                            presentingNextPage = true /// set to true
                        }
                    }
                    
                }
            }
        }
        
        func update() {
            things = []
            for i in 0...count {
                things.append(String(i))
            }
        }
    }
    

    Result:

    Press button to present next page, pressing back doesn't automatically present again.