Search code examples
swiftuiswiftui-list

SwiftUI nested list calls navigationLink prior to selection


I am running into an issue with a nested list in Swift UI where it seems that every list item is making a call to its respective navigationLink regardless of being selected and ignoring the fact that it's disabled, and I'm not sure about why this happens. My code is below, with most of the swift formatting removed-

struct Team: Identifiable {
    let id = UUID()
    let name: String
    let icon: String
    let teamCode: String
    let showTeam: Bool
    var items: [Team]?
}


struct NFLView: View {
    var userPlayEstimates : UserPlayData
    var userAllRosters : userAllRosters
    
    let items: [Team] = [.AFCNorth, .AFCSouth, .AFCEast,.AFCWest]
    
    var body: some View {
        VStack{
            NavigationStack{
                Image("NFL_Logo")
                    .resizable()
                List(items, children: \.items) {row in
                    NavigationLink{
                        NFLTeamRosterView(teamName : row.name, teamCode: row.teamCode, userAllRosters : userAllRosters)
                    } label: {
                        Text(row.name)
                    }
                    .disabled(!row.showTeam)
                }
            }  
        }
    }
}

extension Team {
    static let rai = Team(name:"Raiders", icon:"RAI_Logo", teamCode:"rai", showTeam:true)
    static let rav = Team(name:"Ravens", icon:"BAL_Logo", teamCode:"rav", showTeam:true)
    static let mia = Team(name:"Dolphins", icon:"MIA_Logo", teamCode:"mia", showTeam:true)
    static let buf = Team(name:"Bills", icon:"BUF_Logo", teamCode:"buf", showTeam:true)
    static let nwe = Team(name:"Patriots", icon:"NWE_Logo", teamCode:"nwe", showTeam:true)
    static let nyj = Team(name:"Jets", icon:"NYJ_Logo", teamCode:"nyj", showTeam:true)
    static let cin = Team(name:"Bengals", icon:"CIN_Logo", teamCode:"cin", showTeam:true)
    static let pit = Team(name:"Steelers", icon:"PIT_Logo", teamCode:"pit", showTeam:true)
    static let cle = Team(name:"Browns", icon:"CLE_Logo", teamCode:"cle", showTeam:true)
    static let jax = Team(name:"Jaguars", icon:"JAX_Logo", teamCode:"jax", showTeam:true)
    static let oti = Team(name:"Titans", icon:"OTI_Logo", teamCode:"oti", showTeam:true)
    static let clt = Team(name:"Colts", icon:"CLT_Logo", teamCode:"clt", showTeam:true)
    static let htx = Team(name:"Texans", icon:"HTX_Logo", teamCode:"htx", showTeam:true)
    static let kan = Team(name:"Chiefs", icon:"KAN_Logo", teamCode:"kan", showTeam:true)
    static let sdg = Team(name:"Chargers", icon:"SDG_Logo", teamCode:"sdg", showTeam:true)
    static let den = Team(name:"Broncos", icon:"DEN_Logo", teamCode:"den", showTeam:true)
    
    
    static let AFCWest = Team(name: "AFC West", icon: "NFL_Logo", teamCode:"AFCW", showTeam:false, items: [Team.rai, Team.kan, Team.sdg, Team.den])
    static let AFCNorth = Team(name: "AFC North", icon: "NFL_Logo", teamCode:"AFCN", showTeam:false, items: [Team.rav, Team.pit, Team.cle, Team.cin])
    static let AFCSouth = Team(name: "AFC South", icon: "NFL_Logo", teamCode:"AFCS", showTeam:false, items: [Team.jax, Team.oti, Team.htx, Team.clt])
    static let AFCEast = Team(name: "AFC East", icon: "NFL_Logo",  teamCode:"AFCE", showTeam:false, items: [Team.nwe, Team.mia, Team.nyj, Team.buf])
}

For background, NFLTeamRosterView is designed to accept any team, not an AFC division input, thus the reason for it being disabled as a selectable list item. Any time I make a call to this view though (in particular I'm showing a sheet with NFLView(userPlayEstimates: userPlays, userAllRosters: userRosters), I get an immediate error from NFLTeamRosterView- it's being called on my first list item - NFLTeamRosterView(teamName : "AFC North", teamCode : "AFCN")

Obviously this is a problem in that it causes issues I'd have to design around, but does it also mean that any time I'm creating this nested list that every navigationLink is being run? This seems like a pretty big computation drain if so, and is there a way to prevent that from happening?


Solution

  • This is expected behaviour in SwiftUI. You could try using if/else instead of disabling the link:

    struct NFLView: View {
        var userPlayEstimates : UserPlayData
        var userAllRosters : userAllRosters
        
        let items: [Team] = [.AFCNorth, .AFCSouth, .AFCEast,.AFCWest]
        
        var body: some View {
            VStack{
                NavigationStack{
                    Image("NFL_Logo")
                        .resizable()
                    List(items, children: \.items) { row in
                        if row.showTeam {
                            NavigationLink{
                                NFLTeamRosterView(teamName : row.name, teamCode: row.teamCode, userAllRosters : userAllRosters)
                            } label: {
                                Text(row.name)
                            }
                        } else {
                            Text(row.name)
                        }
                    }
                }  
            }
        }
    }