jianjian
jianjian

Reputation: 88

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

Upvotes: 4

Views: 1582

Answers (2)

aheze
aheze

Reputation: 30506

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.

Upvotes: 3

Put "onAppear{...}" on the NavigationView not the List, like this:

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])
                }
            }
            .navigationTitle("a")
            .toolbar{
                NavigationLink(destination: Subview(count: $count), label: {
                    Text("sub")
                })
            }
        }
        .onAppear {   // <---
            update()
        }
    }

Upvotes: 0

Related Questions