@@ -3,31 +3,7 @@ import SwiftUI
33extension DependencyValues {
44 /// An effect that dismisses the current presentation.
55 ///
6- /// Execute this in the effect returned from a reducer in order to dismiss the feature:
7- ///
8- /// ```swift
9- /// struct ChildFeature: ReducerProtocol {
10- /// struct State { /* ... */ }
11- /// enum Action {
12- /// case exitButtonTapped
13- /// // ...
14- /// }
15- /// @Dependency(\.dismiss) var dismiss
16- /// func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
17- /// switch action {
18- /// case .exitButtonTapped:
19- /// return .fireAndForget { await self.dismiss() }
20- /// // ...
21- /// }
22- /// }
23- /// }
24- /// ```
25- ///
26- /// This operation works by finding the nearest parent feature that was presented using either the
27- /// ``ReducerProtocol/ifLet(_:action:destination:fileID:line:)`` or the
28- /// ``ReducerProtocol/forEach(_:action:destination:fileID:line:)`` operator, and then
29- /// dismisses _that_ feature. If no such parent feature is found a runtime warning is emitted in
30- /// Xcode letting you know that it is not possible to dismiss.
6+ /// See the documentation of ``DismissEffect`` for more information.
317 public var dismiss : DismissEffect {
328 get { self [ DismissKey . self] }
339 set { self [ DismissKey . self] = newValue }
@@ -58,9 +34,43 @@ extension DependencyValues {
5834///
5935/// This operation works by finding the nearest parent feature that was presented using either the
6036/// ``ReducerProtocol/ifLet(_:action:destination:fileID:line:)`` or the
61- /// ``ReducerProtocol/forEach(_:action:destination:fileID:line:)`` operator, and then dismisses
62- /// _that_ feature. If no such parent feature is found a runtime warning is emitted in Xcode letting
63- /// you know that it is not possible to dismiss.
37+ /// ``ReducerProtocol/forEach(_:action:destination:fileID:line:)`` operator, and then
38+ /// dismisses _that_ feature. It performs the dismissal by either sending the
39+ /// ``PresentationAction/dismiss`` in the case of `ifLet` or sending ``StackAction/popFrom(id:)``
40+ /// in the case of `forEach`.
41+ ///
42+ /// It is also possible to dismiss the feature using an animation by providing an argument to the
43+ /// `dismiss` function:
44+ ///
45+ /// ```swift
46+ /// case .exitButtonTapped:
47+ /// return .fireAndForget { await self.dismiss(animation: .default) }
48+ /// ```
49+ ///
50+ /// This will cause the `dismiss` or `popFrom(id:)` action to be sent with the particular animation.
51+ ///
52+ /// > Warning: The `@Dependency(\.dismiss)` tool only works for features that are presented using
53+ /// > the `ifLet` operator for tree-based navigation (see <doc:TreeBasedNavigation> for more info)
54+ /// > or `forEach` operator for stack-based navigation (see <doc:StackBasedNavigation>). If no
55+ /// > parent feature is found that was presented with `ifLet` or `forEach`, then a runtime warning
56+ /// > is emitted in Xcode letting you know that it is not possible to dismiss. Further, the runtime
57+ /// > warning becomes a test failure when run in tests.
58+ /// >
59+ /// > If you are testing a child feature in isolation that makes use of `@Dependency(\.dismiss)`
60+ /// > then you will need to override the dependency to get a passing test. You can even mutate
61+ /// > some shared mutable state inside the `dismiss` closure to confirm that it is indeed invoked:
62+ /// >
63+ /// > ```swift
64+ /// > let isDismissInvoked = LockIsolated(false)
65+ /// > let store = Store(initialState: Child.State(), reducer: Child()) {
66+ /// > $0.dismiss = { isDismissInvoked.setValue(true) }
67+ /// > }
68+ /// >
69+ /// > await store.send(.exitButtonTapped) {
70+ /// > // ...
71+ /// > }
72+ /// > XCTAssertEqual(isDismissInvoked.value, true)
73+ /// > ```
6474public struct DismissEffect : Sendable {
6575 var dismiss : ( @MainActor @Sendable ( ) -> Void ) ?
6676
0 commit comments