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.