You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NavigationStack传参异常:所有详情页均显示‘First’

问题描述

将News结构体数据传入NavigationStack深层导航页面时出现异常:明明有三组不同的数据,但所有详情页的标签都显示First。只有点击第一个单元格时能获取正确数据,其余单元格点击后详情页数据都不对。

场景:

  • 用户点击第一个单元格,能看到正确的详情数据
  • 用户点击第二、第三个单元格,详情页依然显示First

演示动图

以下是问题代码:

struct HomeView: View {
    @Binding var navPath: NavigationPath
    
    var body: some View {
        NavigationStack(path: $navPath) {
            TabView {
                ListView(navPath: $navPath)
                    .tabItem {
                        Label("First", systemImage: "newspaper")
                    }
            }
        }
    }
}

struct ListView: View {
    @Binding var navPath: NavigationPath
    let news: [News] = [.init(name: "First"), .init(name: "Second"), .init(name: "Third")]
    var body: some View {
        NavigationStack(path: $navPath) {
            List(news) { new in
                CellView(news: new, navPath: $navPath)
            }
        }
    }
}

enum CellRouter: Hashable {
    case details
}

struct CellView: View {
    let news: News
    @Binding var navPath: NavigationPath
    
    var body: some View {
        NavigationStack(path: $navPath) {
            HStack {
                Button(news.name) {
                    navPath.append(CellRouter.details)
                }
            }
            .navigationDestination(for: CellRouter.self) { router in
                switch router {
                case .details:
                    CellViewDetails(news: news, navPath: $navPath)
                }
            }
        }
    }
}

struct News: Identifiable {
    var id: String { name }
    let name: String
}

struct CellViewDetails: View {
    let news: News
    @Binding var navPath: NavigationPath
    
    var body: some View {
        NavigationStack(path: $navPath) {
            Text(news.name)
        }
    }
}
问题原因
  1. 多层NavigationStack嵌套:代码在HomeView、ListView、CellView、CellViewDetails中重复嵌套NavigationStack,完全违背SwiftUI导航的设计逻辑——一个完整的导航流程只需要**最外层一个NavigationStack**即可。
  2. 导航目的地冲突:每个CellView都注册了CellRouter.self类型的导航目的地,当点击按钮将CellRouter.details加入导航路径时,系统会匹配到第一个注册该类型目的地的视图(即列表里第一个CellView),因此无论点击哪个单元格,都会跳转到第一个CellView对应的详情页,显示First。
优化后的实现方式

最简洁的方案是移除所有多余的NavigationStack,仅保留最外层的一个,同时直接将News对象加入导航路径,无需额外的CellRouter枚举,这样能直接在导航目的地中获取对应数据:

struct HomeView: View {
    @Binding var navPath: NavigationPath
    
    var body: some View {
        NavigationStack(path: $navPath) {
            TabView {
                ListView()
                    .tabItem {
                        Label("First", systemImage: "newspaper")
                    }
            }
            // 统一注册导航目的地
            .navigationDestination(for: News.self) { news in
                CellViewDetails(news: news)
            }
        }
    }
}

struct ListView: View {
    let news: [News] = [.init(name: "First"), .init(name: "Second"), .init(name: "Third")]
    
    var body: some View {
        List(news) { new in
            // 使用NavigationLink直接绑定News数据
            NavigationLink(value: new) {
                Text(new.name)
            }
            // 也可以用按钮方式:
            // Button(new.name) {
            //     navPath.append(new)
            // }
        }
    }
}

struct News: Identifiable, Hashable {
    var id: String { name }
    let name: String
}

struct CellViewDetails: View {
    let news: News
    
    var body: some View {
        Text(news.name)
            .navigationTitle(news.name)
    }
}

如果需要保留CellRouter的设计,可以让枚举携带News数据,避免上下文匹配冲突:

enum CellRouter: Hashable {
    case details(News)
}

// CellView中的按钮逻辑修改为:
Button(news.name) {
    navPath.append(CellRouter.details(news))
}

// 导航目的地处理逻辑修改为:
.navigationDestination(for: CellRouter.self) { router in
    switch router {
    case .details(let news):
        CellViewDetails(news: news)
    }
}

核心原则:

  • 一个导航层级仅保留一个NavigationStack
  • 导航路径中直接携带需要传递的数据,或让路由枚举承载数据,避免依赖视图上下文匹配目的地

内容的提问来源于stack exchange,提问作者miltenkot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 13:43:10