Replies: 5 comments 11 replies
-
It looks like there are a few other posts in the forum raising the same, or a related, issue:
The last one may hold the solution to the problem I'm raising here. More specifically, I'm intrigued by @stephencelis's comment in that last thread whereby he says
so I'll investigate further and will report back soon. |
Beta Was this translation helpful? Give feedback.
-
I did find a solution where the state of the presented view is scoped from the state of the presenting view but it seems to work only if/when the state of the child is scoped at the time the child view is initialised, as follows: public struct View: SwiftUI.View {
@SwiftUI.Environment(\.dismiss) private var dismiss
private let store: Store<State, Action>
@ObservedObject private var viewStore: ViewStore<State, Action>
private var destination: IfLetStore<BScene.State, BScene.Action, BScene.View?>
private var isActive: Binding<Bool>
public init(store: Store<State, Action>) {
self.store = store
let viewStore = ViewStore(store)
self.viewStore = viewStore
let childStore = store.scope(
state: { $0.routeState(for: /State.Route.child) },
action: Action.child
)
self.destination = IfLetStore(childStore, then: BScene.View.init(store:))
self.isActive = viewStore.binding(
get: { $0.isRoutingTo(/State.Route.child) },
send: Action.presentChild
)
}
public var body: some SwiftUI.View {
VStack {
// ...
Button(action: { viewStore.send(.presentChild(true)) }) { Text("Push") }
NavigationLink("", destination: destination, isActive: isActive)
// ...
}
// ...
}
} It's not clear to me that this solution is free from problems but it appears to work. This solution has been added to the toy project repository as a second package, |
Beta Was this translation helpful? Give feedback.
-
The The easiest way of doing this is by scoping the store before passing on to |
Beta Was this translation helpful? Give feedback.
-
I didn’t checked your example but point free released a lib for navigation |
Beta Was this translation helpful? Give feedback.
-
@stephencelis @mbrandonw Here are some pretty convenient concepts for navigation are implemented here https://github.com/CaptureContext/composable-architecture-extensions/tree/main/Sources/ComposableNavigation (example in repo is outdated + the package has some private dependencies yet (@pointfree have full access, but each library is on a prototyping stage yet, so a bunch of things may change, hopefully I'll be able to open-source everything by the end of the year)).
I'll be posting updates here when I push useful additions to the TCA-Extensions repo's ComposableNavigation target Plus one more ping for PR#847, this is not actually a routing problem, but sync for |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Good day everyone!
I'm attempting to use the routing ideas currently being discussed in the video series within TCA but I ran into a very unusual situation. In the example project I created, you can either present a series of nested scenes using a sheet presentation style or a stack navigation style.
The navigation works perfectly with sheet presentation but fails with stack navigation. It works fine when scene A pushes scene B but when scene B then pushes scene C, scene C appears for a brief moment then gets dismissed back to scene B, which is then left in an inconsistent state.
The code that calls them is identical and the data passed to them is identical, except for the fact that a sheet takes a closure that produces its destination view while a
NavigationLink
takes the actual view, ie, theNavigationLink
API is "eager". Using a lazy wrapper view to build the view only when it's actually presented does not solve the issue so, in effect, both the sheet and theNavigationLink
take the exact same data.I thought that maybe it's the logic in the reducer that is at fault but, if that was the case, why would the sheet presentation work flawlessly? Besides, the reducer logic is pretty simple and all the debug actions and state changes, in both sheets and nav links, are correct. In fact, the state after A pushes B and B pushes C is exactly what you'd expect but that is not what is rendered.
I then thought that since everything is effectively the same for both sheets and nav links, then the fact that the former work but the latter don't suggests that there's a bug in the implementation of
NavigationLink
itself, ie, a bug in SwiftUI itself.So, I built an identical project using vanilla SwiftUI and the navigation links work perfectly fine.
The next alternative is that TCA itself has a bug but, then, its code is agnostic with respect to the rendering framework so if it works with sheets, it should also work with nav links.
The only alternative left is that I don't correctly understand how to model this problem but, then, this is a really simple project: just identical scenes that present one another in sequence, in a nested way (A presents B, then B presents C, then C presents D, then D presents some leaf scene).
I did find a solution, however. When creating the destination view, do not scope the presenting store down to the presented store but, rather, create a brand new store with the presented state. In code, it means to use
rather than
This solution smells wrong in at least three ways:
I'm at a loss in what should be a really simple problem. At work, it's become a blocker, which is why I created a toy project and also why I'm here at the forum asking for help.
Any help is much appreciated!
Beta Was this translation helpful? Give feedback.
All reactions