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

SwiftUI .toolbar中NavigationLink模型变更时生成多余嵌套子视图如何解决

问题原因

根因是store.user为@Published修饰的响应式属性,每次用户信息更新都会触发ContentView的body重绘。你当前把NavigationLink直接放在Toolbar内,且NavigationLink的初始化直接依赖store.user,重绘时如果已经处于SettingsView的push状态,系统会识别为新的导航目标,重复push新的SettingsView实例,最终形成视图堆叠。

解决方案

方案1:适配iOS13+,用isActive绑定控制导航

核心是把NavigationLink和Toolbar解耦,用独立的状态变量控制导航触发,不受user属性更新影响:

struct ContentView: View {
    @EnvironmentObject var store: Store
    // 独立的导航控制状态
    @State private var showSettings = false
    
    var body: some View {
        NavigationView {
            HomeView()
                .toolbar {
                    ToolbarItemGroup(placement: .navigationBarTrailing) {
                        if store.user != nil {
                            // 按钮仅负责修改导航状态
                            Button {
                                showSettings = true
                            } label: {
                                Text("Edit user")
                            }
                        }
                    }
                }
                // NavigationLink移到视图层级底部,和Toolbar解耦
                .background(
                    NavigationLink(isActive: $showSettings) {
                        SettingsView()
                    } label: {
                        EmptyView()
                    }
                )
        }
    }
}

// SettingsView直接从环境变量读取user即可,无需外部传参
struct SettingsView: View {
    @EnvironmentObject var store: Store
    
    var body: some View {
        Text(store.user?.username ?? "")
        Button {
            store.updateUser(to: "New username")
        } label: {
            Text("Update username")
        }
    }
}

方案2:适配iOS16+,用NavigationStack实现程序化导航

新版导航栈API对动态导航的兼容性更好,完全避免意外push的问题:

struct ContentView: View {
    @EnvironmentObject var store: Store
    @State private var navPath = NavigationPath()
    
    enum NavRoute: Hashable {
        case settings
    }
    
    var body: some View {
        NavigationStack(path: $navPath) {
            HomeView()
                .toolbar {
                    ToolbarItemGroup(placement: .navigationBarTrailing) {
                        if store.user != nil {
                            Button {
                                navPath.append(NavRoute.settings)
                            } label: {
                                Text("Edit user")
                            }
                        }
                    }
                }
                .navigationDestination(for: NavRoute.self) { route in
                    switch route {
                    case .settings:
                        SettingsView()
                    }
                }
        }
    }
}

补充说明

  • 不要把NavigationLink直接放在会频繁重绘的Toolbar节点下,用独立状态控制导航触发是最稳妥的方案。
  • 如果需要给SettingsView传参,直接在目标视图内从环境变量读取store.user即可,不要作为NavigationLink的入参传入,避免依赖变更触发的视图重绘导致导航异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 04:57:05