2

I'm using a custom NavigationButton from this answer to be able to load data for a specific view when navigating to a new view from a list. It works great, but the problem is when I attempt to use it inside a ForEach loop I end up with the multiple navigation links with multiple isActive @State variables that are all being told to push a new view, which causes SwiftUI to navigate to the new view then automatically back to parent view (bug). How can I preserve the functionality of being able to fire code to run while navigating to a new view without triggering the bug.

ForEach(workouts) { workout in
    NavigationButton(
        action: {
            //load data for Destination
        },
        destination: {
            WorkoutDetailView().environmentObject(dataStore)
        },
        workoutRow: { WorkoutRow(trackerWorkout: workout) }
    )
    
}

struct NavigationButton<Destination: View, WorkoutRow: View>: View {
    var action: () -> Void = { }
    var destination: () -> Destination
    var workoutRow: () -> WorkoutRow
    
    @State private var isActive: Bool = false
    
    var body: some View {
        Button(action: {
            self.action()
            self.isActive.toggle()
        }) {
            workoutRow()
                .background(
                    ScrollView { // Fixes a bug where the navigation bar may become hidden on the pushed view
                        NavigationLink(destination: LazyDestination { self.destination() },
                                       isActive: self.$isActive) { EmptyView() }
                    }
                )
        }
    }
}

// This view lets us avoid instantiating our Destination before it has been pushed.
struct LazyDestination<Destination: View>: View {
    var destination: () -> Destination
    var body: some View {
        self.destination()
    }
}
aheze
  • 24,434
  • 8
  • 68
  • 125
GarySabo
  • 5,806
  • 5
  • 49
  • 124
  • What kind of data are you loading? seems like an odd setup. Why not have it ready to go in the `dataStore` or in the `workout`? `WorkoutDetailView()` should look something like this in a "normal" setup `WorkoutDetailView(workout: workout)`. Tough to help without more info. That `NavigationButton` does not seem right either because you are not using `ViewBuilder` anywhere. – lorem ipsum Jun 01 '21 at 13:47
  • @loremipsum its loading specific info (e.g. heart rates etc.) from a given workout so as not to load all the data from all workouts up front for performance reasons. – GarySabo Jun 01 '21 at 14:18
  • If you are loading stuff from CoreData, another database service or HealthKit it is likely too much for a View. A View should never do work it is for UI. Load it in the Detail View – lorem ipsum Jun 01 '21 at 14:41

0 Answers0