NavigationLink does not work with TCA binding but works fine in vanilla SwiftUI @State

While using TCA I am facing this issue for the first time ever:

if I use a NavigationLink isActive with vanilla SwiftUI @State it works just fine

NavigationLink(
    destination: MapDetailView(store: self.store),
    isActive: $showDetailView
) {
    Button {
        showDetailView = true
    } label: {
        Text("SHOW DETAIL")
    }
}

but if I use the TCA way of handling the binding it won't work, although I have used the same approach multiple times and it works just fine but not in this case.

NavigationLink(
    destination: MapDetailView(store: self.store),
    isActive: viewStore.binding(
         get: { $0.route == .showDetailView(true) },
         send: MapsFeature.Action.setDetailView(isPresented:)
    )
) {
    Button {
        viewStore.send(.setDetailView(isPresented: true))
    } label: {
        Text("SHOW DETAIL")
    }
}

I don't know the internals of your implementation, but the most approximated solution to your vanilla SwiftUI solution should be:

public struct State: Equatable {
    @BindingState public var showDetailView: Bool
}

public enum Action: BindableAction, Equatable {
    case binding(BindingAction<State>)
}

public var body: some ReducerProtocol<State, Action> {
    BindingReducer()
    Reduce<State, Action> { state, action in
        case .binding(\.$showDetailView):
            // You can control when showDetailView value gets toggled
            return .none

        case .bind:
            return .none
        }
    }
}

And now you can bind it directly:

isActive: viewStore.binding(\.$showDetailView)

Hope it helps

1 Like

Can you share how you instantiate your viewStore @saifullahsajid ? Is it via WithViewStore or explicit init? The thing is that with an explicit init it may not get retained by SwiftUI unless you keep it explicitly as an @ObservedObject. Maybe that's the case?

1 Like

So this was something really strange. Initially, I fixed this by toggling the state from a parent. But later on, even that stopped working and the final fix was to remove an unnecessary nested child from the hierarchy and the it worked in that same view.