1

Weird issue using new NavigationStack. When trying to push the DrinkView for the second time, it's pushed twice and the OrderFood gets view removed from the navigation.

The reason is @Published var openDrinks in the View Model. Is there is any way to solve this issue. Thanks.

import SwiftUI


struct ContentView: View {
    var body: some View {
        NavigationStack {
            VStack {
                
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                NavigationLink("Hello", value: "Amr")
//                Text("Hello, world!")
            }
            .navigationTitle("Main")
            .padding()
            .navigationDestination(for: String.self) { value in
                OrderFood(viewModel: ViewModel())
            }
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}




class ViewModel: ObservableObject {
    @Published var openDrinks: Bool = false
}

struct OrderFood: View {
    @ObservedObject var viewModel: ViewModel
//    @ObservedObject var viewModel = ViewModel()
    var body: some View {
        VStack {
            Text("Add Drink")
                .onTapGesture {
                    viewModel.openDrinks = true
                }
        }
        .navigationTitle("Order Food")
        .navigationDestination(isPresented: $viewModel.openDrinks) {
            DrinksView()
                .navigationTitle("Drinks")
        }
        .onAppear {
            viewModel.openDrinks = false
        }
    }
}

struct OrderFood_Previews: PreviewProvider {
    static var previews: some View {
        OrderFood(viewModel: ViewModel())
    }
}

import SwiftUI

struct DrinksView: View {
    
    var body: some View {
        NavigationLink("Ch") {
            Text("Hello, World!")
        }
    }
}

struct DrinksView_Previews: PreviewProvider {
    static var previews: some View {
        DrinksView()
    }
}
Timmy
  • 4,098
  • 2
  • 14
  • 34

1 Answers1

1

In ContentView, you use OrderFood(viewModel: ViewModel()), which means you create a new ViewModel every time you navigate to OrderFood.

Try this approach, where you have one source of truth, that you pass to the details view:

struct ContentView: View {
    @StateObject var viewModel = ViewModel()  // <-- here

    var body: some View {
        NavigationStack {
            VStack {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                NavigationLink("Hello", value: "Amr")
            }
            .navigationTitle("Main")
            .padding()
            .navigationDestination(for: String.self) { value in
                OrderFood(viewModel: viewModel) // <-- here
            }
        }
        
    }
}

Note, you could also use @EnvironmentObject in this case.

EDIT-1: using @EnvironmentObject to pass the viewModel around:

struct ContentView: View {
    @StateObject var viewModel = ViewModel()  // <-- here
    var body: some View {
        NavigationStack {
            VStack {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                NavigationLink("Hello", value: "Amr")
            }
            .navigationTitle("Main")
            .padding()
            .navigationDestination(for: String.self) { value in
                OrderFood() // <-- here
            }
        }.environmentObject(viewModel)  // <-- here
        
    }
}

struct OrderFood: View {
    @EnvironmentObject var viewModel: ViewModel  // <-- here
    
    var body: some View {
        VStack {
            Text("Add Drink")
                .onTapGesture {
                    viewModel.openDrinks = true
                }
        }
        .navigationTitle("Order Food")
        .navigationDestination(isPresented: $viewModel.openDrinks) {
            DrinksView().navigationTitle("Drinks")
        }
        .onAppear {
            viewModel.openDrinks = false
        }
    }
}