-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DismissEffect not working in combination with NavigationStack and await store.send(...).finish() in stack's root view #3527
Comments
We are also experiencing this issue and I really don't think using At least I think we need better documentation and test coverage on the semantics of cancellation with the navigation utilities. The current implementation seems to set up and remove cancellation handlers quite (overly?) deliberately1. While studying the issue, I found at least one workaround which seems to fix the above sample project, but I don't fully understand why: // RootFeature.swift
@_spi(Internals) import ComposableArchitecture
...
switch action {
case .task:
@Dependency(\.stackElementID) var stackElementID
return .send(.navigation(.path(.push(
id: stackElementID(),
state: .detail(DetailFeature.State())
))))
...
} Footnotes
|
When deep linked instead of using task in the
I couldn't find time to investigate deeper but I can clearly see |
@mbrandonw @stephencelis Did you already have time to look into this issue? By further investigating the issue based on the sample project (see description) I suspect the following cause: It seems that when initializing the Code from StackReducer.swift#L509-L525: destinationEffects = self.destination
.dependency(
\.dismiss,
DismissEffect { @MainActor in
Task._cancel(
id: NavigationDismissID(elementID: elementID), // <- here the id is 'NavigationDismissID(elementID:)'
navigationID: elementNavigationIDPath
)
}
)
.dependency(\.navigationIDPath, elementNavigationIDPath)
.reduce(
into: &state[keyPath: self.toStackState][id: elementID]!,
action: destinationAction
)
.map { [toStackAction] in toStackAction.embed(.element(id: elementID, action: $0)) }
._cancellable(navigationIDPath: elementNavigationIDPath) // <- here the id is '_PresentedID()' because of the default argument So when clicking the close button and executing the let cancelID = _CancelID(id: id, navigationIDPath: path)
self.storage[cancelID]?.forEach { $0.cancel() }
self.storage[cancelID] = nil The
So I think the fix for this issue would be to use the same cancel Additionally, I also noticed that the issue is not only happening when using a NavigationStack but also happens sometimes when using a sheet. This seems to be the same cause as described above because the sheet PresentationReducer also creates a Code from PresentationReducer.swift#L605-L617: destinationEffects = self.destination
.dependency(
\.dismiss,
DismissEffect { @MainActor in
Task._cancel(id: PresentationDismissID(), navigationID: destinationNavigationIDPath) // <- here the id is 'PresentationDismissID()'
}
)
.dependency(\.navigationIDPath, destinationNavigationIDPath)
.reduce(
into: &state[keyPath: self.toPresentationState].wrappedValue!, action: destinationAction
)
.map { [toPresentationAction] in toPresentationAction.embed(.presented($0)) }
._cancellable(navigationIDPath: destinationNavigationIDPath) // <- here the id is '_PresentedID()' because of the default argument |
Description
In the provided sample project, the app's root view's task action, the RootFeature, appends a feature state (DetailFeature) to the navigation path on the app's NavigationStack. When pressing the DetailFeature's close button, it calls the
DismissEffect
. The detail view, however, doesn't get dismissed. I figured out this is because the NavigationStack's root view (HomeView) awaits the send action to finish in the task view modifier.Checklist
main
branch of this package.Expected behavior
The view pushed onto the NavigationStack should pop when calling
dismiss
.Actual behavior
The view is not getting removed from the stack.
Reproducing project
Sample project: dismiss.zip
The dismiss is not working when using
.task { await store.send(.task).finish() }
in HomeView (which is the NavigationStack root view):The dismiss only works when just using
.task { store.send(.task) }
in HomeView.The Composable Architecture version information
1.17.0
Destination operating system
iOS 18
Xcode version information
Xcode version 16.0 (16A242d)
Swift Compiler version information
The text was updated successfully, but these errors were encountered: