canopas / UIPilot

The missing typesafe SwiftUI navigation library
https://canopas.github.io/UIPilot
MIT License
309 stars 27 forks source link

Passing state from the router view to subviews #20

Closed denizdogan closed 2 years ago

denizdogan commented 2 years ago

When using UIPilot for navigation, state that is updated in the view that holds the UIPilotHost doesn't get properly passed to subviews. Is this a known limitation?

struct MyRootView: View {
    @StateObject var pilot: UIPilot<MyRoute> = UIPilot(initial: .preparing)
    @StateObject var vm: MyRootViewModel = .init()

    var body: some View {
        UIPilotHost(pilot) { route in
            switch route {
            case .foobar:
                return AnyView(MySubView(vm: vm))
...

struct MySubView: View {
    @ObservedObject var vm: MyRootViewModel

    var body: some View {
        Text(vm.somePropertyThatChanges)

When changing vm.somePropertyThatChanges (which is a @Published variable) using the above, the body of MySubView won't be re-rendered. It seems to work fine when using plain NavigationView. Is this a limitation with AnyView somehow?

jimmy0251 commented 2 years ago

Works fine for me

enum MyRoute: Equatable {
    case Home
    case Detail
}

struct ContentView3: View {

    @StateObject var pilot: UIPilot<MyRoute> = UIPilot(initial: .Home)
    @StateObject var vm: MyRootViewModel = .init()

    var body: some View {
        UIPilotHost(pilot) { route in
            switch(route) {
            case .Home: return AnyView(Home())
            case .Detail: return AnyView(Detail(vm: vm))
            }
        }
    }
}

class MyRootViewModel: ObservableObject {

    @Published var count: Int = 0

    init() {
        increment()
    }

    func increment() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.count += 1
            self.increment()
        }
    }
}

struct Home: View {

    @EnvironmentObject var pilot: UIPilot<MyRoute>

    var body: some View {
        Button {
            pilot.push(.Detail)
        } label: {
            Text("Go to detail")
        }
    }
}

struct Detail: View {

    @ObservedObject var vm: MyRootViewModel

    var body: some View {
        Text("My count \(vm.count)")
    }
}

Works fine for me with the above example. Can you please push the sample project that has the issue?

denizdogan commented 2 years ago

Sorry, must have been some mistake on my part. I honestly don't remember what happened anymore. Closing this, probably invalid bug report!