8.3 C
New York
Tuesday, March 25, 2025

ios – Why do we have to inject the identical object into the surroundings twice in SwiftUI?


I’m making an attempt to create a centralized router for my SwiftUI app and hoped to make the most of the @Surroundings function for this.

Whereas this won’t be the most effective design sample, I’m making an attempt to grasp why the next doesn’t work.

I begin by creating 3 routes

enum Route: String, Hashable {
    case dwelling
    case paywall
    case login
}

I then create this view modifier to arrange my root view with a router:

struct RouterViewModifier: ViewModifier {
    @State personal var router = Router()
    
    @ViewBuilder
    personal func routeView(for route: Route) -> some View {
        change route {
        case .login:
            LoginView()
            
        case .dwelling, .paywall:
            Textual content(route.rawValue)
        }
    }
    
    func physique(content material: Content material) -> some View {
        NavigationStack(path: $router.path) {
            content material
                .surroundings(router)
                .navigationDestination(for: Route.self) { route in
                    routeView(for: route)
                }
        }
    }
}

extension View {
    func withRouter() -> some View {
        modifier(RouterViewModifier())
    }
}

You may see the .surroundings(router) in my code above the place I assume the router is being injected within the physique perform

I then set my app up like so:

@important
struct SwiftUI_CoordinatorApp: App {
    var physique: some Scene {
        WindowGroup {
            RootView()
                .withRouter()
        }
    }
}

struct RootView: View {
    @Surroundings(Router.self) var router: Router?
    
    var physique: some View {
        ZStack {
            Textual content("Splash")
                .onAppear {
                    DispatchQueue.important.asyncAfter(deadline: .now() + 2) {
                        router?.navigate(to: .login)
                    }
                }
        }
        .body(maxWidth: .infinity, maxHeight: .infinity)
        .background(.yellow)
        
    }
}

struct LoginView: View {
    @Surroundings(Router.self) var router: Router?
    
    var physique: some View {
        VStack {
            Button("Login") {
                router?.navigate(to: .dwelling)
            }
        }
        .toolbar(.hidden)
        .padding()
    }
}

So my RootView which serves as a splash display will get arrange and after 2 seconds, the router pushes to the login view as anticipated.

Nevertheless, now as soon as I’m on the LoginView, once I faucet the button nothing occurs and the router is nil.

This will get mounted if in my second code snippet the place I’ve personal func routeView(for route: Route) -> some View { I add .surroundings(router) – every little thing begins working as anticipated.

So that’s:

@ViewBuilder
personal func routeView(for route: Route) -> some View {
    Group {
        change route {
        case .login:
            LoginView()
            
        case .dwelling, .paywall:
            Textual content(route.rawValue)
        }
    }
    .surroundings(router)
}

I do not get why I have to inject the router into the surroundings twice. Should not doing it as soon as on the content material within the navigation stack degree be sufficient for all subsequent views within the app to entry it except it’s faraway from the surroundings ?

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles