Home > other >  User navigated to Parent screen when data fetched on onChange and displayed using ForEach
User navigated to Parent screen when data fetched on onChange and displayed using ForEach

Time:09-23

View1 has a StateObject that runs a timer. When the timer condition is met, Views1's onChange() is called which refetches data. This data is shown using ForEach.

Inside ForEach, we have NavigationLink to View2. Say user is now in View2 screen.

But whenever the time condition is met on View1, even if the user is in the View2 screen, View1 gets shown. Why is this? And this works when there is no ForEach.

Is Foreach the issue? What could be done to let users remain on whatever screen there are? Thanks.

Github code showing problem: https://github.com/Kavisha-Dev/BackToParentPageIssue

Video showing issue: https://kapwi.ng/c/4IbfdigRWr

CodePudding user response:

Try this in CotentView:

struct ContentView: View {
    @StateObject var todayMealStore: TodayMealStore = TodayMealStore()
    @StateObject private var evilObject = TimerStateObject()
    @State var index = 0
    @State var stopTimer = false
    var body: some View {
        NavigationView {
            VStack {
                if todayMealStore.todaysMeals.count > 0 {
                    NavigationLink(destination: SampleView01(mealCategoryName: todayMealStore.todaysMeals[0].name)) {
                        Text("Single Object: Tap me : \(todayMealStore.todaysMeals[0].name)")
                            .foregroundColor(.green)
                    }.padding()
                }
                /*iOS <  15 //don't forget to uncomment the code you require
                ForEach(todayMealStore.todaysMeals) { item in
                    NavigationLink(destination: SampleView01(mealCategoryName: item.name), isActive: getBinding(item)) {
                        Text("ForEach item: Tap me : \(item.name)")
                            .foregroundColor(.green)
                    }.padding()
                }*/
                /*iOS > 15
                ForEach($todayMealStore.todaysMeals) { $item in
                    NavigationLink(destination: SampleView01(mealCategoryName: item.name), isActive: $item.stopTimer) {
                        Text("ForEach item: Tap me : \(item.name)")
                            .foregroundColor(.green)
                    }.padding()
                }*/
                NavigationLink(destination: SampleView02(name: "Another View")) {
                    Text("Tap me")
                } .padding()
            }.onAppear(perform: fetchTodaysMeals)
            .onChange(of: evilObject.changedNumber) { newValue in
                if !todayMealStore.todaysMeals.contains(where: {$0.stopTimer}) {
                    print("ContentView: onChange hit. New Meal Data fetched!")
                    fetchTodaysMeals()
                }
            }.onChange(of: todayMealStore.todaysMeals.contains(where: {$0.stopTimer})) { newValue in
                if !newValue {
                    fetchTodaysMeals()
                }
            }
        }
    }
    func fetchTodaysMeals() {
        todayMealStore.fetch()
    }
    func getBinding(_ item: TodayMealModel) -> Binding<Bool> { //for iOS < 15
        return Binding {
            item.stopTimer
        } set: { value in
            todayMealStore.todaysMeals[todayMealStore.todaysMeals.firstIndex(where: {$0.id == item.id}) ?? 0].stopTimer = value
        }
    }
}

TodayMealModel:

struct TodayMealModel: Identifiable {
    public var id: UUID = UUID()
    var mealId: UUID
    var name: String
    var stopTimer = false
}

Basically what I did is stop the timer from refreshing whenever the NavigationLink is active, and when the NavigationLink gets dismissed, the view automatically gets refreshed.

What you can also do is stop the timer completely instead of stoping the refresh function from being executed.

As to why this happened, because the view keeps refreshing and the passed view (SampleView01) depends on the data that's being refreshed, hence it will dismiss.

  • Related