NavigateAndLoad: Cancel loading on dismiss (#757)

* NavigateAndLoad: Cancel loading on dismiss

* Update Examples/CaseStudies/SwiftUICaseStudies/03-Navigation-NavigateAndLoad.swift

Co-authored-by: Stephen Celis <stephen.celis@gmail.com>

* Update Examples/CaseStudies/SwiftUICaseStudies/03-Navigation-Sheet-PresentAndLoad.swift

Co-authored-by: Stephen Celis <stephen.celis@gmail.com>

* Add cancellation to UIKitCaseStudies/NavigateAndLoad.swift

* Add cancellation to LoadThenNavigate studies

Co-authored-by: Stephen Celis <stephen.celis@gmail.com>
This commit is contained in:
filblue
2021-09-02 00:25:54 +03:00
committed by GitHub
parent 83e7557d7b
commit dacd3de63f
7 changed files with 46 additions and 3 deletions

View File

@@ -26,6 +26,7 @@ struct LoadThenNavigateListState: Equatable {
enum LoadThenNavigateListAction: Equatable { enum LoadThenNavigateListAction: Equatable {
case counter(CounterAction) case counter(CounterAction)
case onDisappear
case setNavigation(selection: UUID?) case setNavigation(selection: UUID?)
case setNavigationSelectionDelayCompleted(UUID) case setNavigationSelectionDelayCompleted(UUID)
} }
@@ -57,6 +58,9 @@ let loadThenNavigateListReducer =
case .counter: case .counter:
return .none return .none
case .onDisappear:
return .cancel(id: CancelId())
case let .setNavigation(selection: .some(navigatedId)): case let .setNavigation(selection: .some(navigatedId)):
for row in state.rows { for row in state.rows {
state.rows[id: row.id]?.isActivityIndicatorVisible = row.id == navigatedId state.rows[id: row.id]?.isActivityIndicatorVisible = row.id == navigatedId
@@ -119,6 +123,7 @@ struct LoadThenNavigateListView: View {
} }
} }
.navigationBarTitle("Load then navigate") .navigationBarTitle("Load then navigate")
.onDisappear { viewStore.send(.onDisappear) }
} }
} }
} }

View File

@@ -17,6 +17,7 @@ struct LoadThenNavigateState: Equatable {
} }
enum LoadThenNavigateAction: Equatable { enum LoadThenNavigateAction: Equatable {
case onDisappear
case optionalCounter(CounterAction) case optionalCounter(CounterAction)
case setNavigation(isActive: Bool) case setNavigation(isActive: Bool)
case setNavigationIsActiveDelayCompleted case setNavigationIsActiveDelayCompleted
@@ -38,12 +39,20 @@ let loadThenNavigateReducer =
with: Reducer< with: Reducer<
LoadThenNavigateState, LoadThenNavigateAction, LoadThenNavigateEnvironment LoadThenNavigateState, LoadThenNavigateAction, LoadThenNavigateEnvironment
> { state, action, environment in > { state, action, environment in
struct CancelId: Hashable {}
switch action { switch action {
case .onDisappear:
return .cancel(id: CancelId())
case .setNavigation(isActive: true): case .setNavigation(isActive: true):
state.isActivityIndicatorVisible = true state.isActivityIndicatorVisible = true
return Effect(value: .setNavigationIsActiveDelayCompleted) return Effect(value: .setNavigationIsActiveDelayCompleted)
.delay(for: 1, scheduler: environment.mainQueue) .delay(for: 1, scheduler: environment.mainQueue)
.eraseToEffect() .eraseToEffect()
.cancellable(id: CancelId())
case .setNavigation(isActive: false): case .setNavigation(isActive: false):
state.optionalCounter = nil state.optionalCounter = nil
@@ -90,6 +99,7 @@ struct LoadThenNavigateView: View {
} }
} }
} }
.onDisappear { viewStore.send(.onDisappear) }
} }
.navigationBarTitle("Load then navigate") .navigationBarTitle("Load then navigate")
} }

View File

@@ -37,17 +37,19 @@ let navigateAndLoadReducer =
with: Reducer< with: Reducer<
NavigateAndLoadState, NavigateAndLoadAction, NavigateAndLoadEnvironment NavigateAndLoadState, NavigateAndLoadAction, NavigateAndLoadEnvironment
> { state, action, environment in > { state, action, environment in
struct CancelId: Hashable {}
switch action { switch action {
case .setNavigation(isActive: true): case .setNavigation(isActive: true):
state.isNavigationActive = true state.isNavigationActive = true
return Effect(value: .setNavigationIsActiveDelayCompleted) return Effect(value: .setNavigationIsActiveDelayCompleted)
.delay(for: 1, scheduler: environment.mainQueue) .delay(for: 1, scheduler: environment.mainQueue)
.eraseToEffect() .eraseToEffect()
.cancellable(id: CancelId())
case .setNavigation(isActive: false): case .setNavigation(isActive: false):
state.isNavigationActive = false state.isNavigationActive = false
state.optionalCounter = nil state.optionalCounter = nil
return .none return .cancel(id: CancelId())
case .setNavigationIsActiveDelayCompleted: case .setNavigationIsActiveDelayCompleted:
state.optionalCounter = CounterState() state.optionalCounter = CounterState()

View File

@@ -17,6 +17,7 @@ struct LoadThenPresentState: Equatable {
} }
enum LoadThenPresentAction { enum LoadThenPresentAction {
case onDisappear
case optionalCounter(CounterAction) case optionalCounter(CounterAction)
case setSheet(isPresented: Bool) case setSheet(isPresented: Bool)
case setSheetIsPresentedDelayCompleted case setSheetIsPresentedDelayCompleted
@@ -38,12 +39,20 @@ let loadThenPresentReducer =
with: Reducer< with: Reducer<
LoadThenPresentState, LoadThenPresentAction, LoadThenPresentEnvironment LoadThenPresentState, LoadThenPresentAction, LoadThenPresentEnvironment
> { state, action, environment in > { state, action, environment in
struct CancelId: Hashable {}
switch action { switch action {
case .onDisappear:
return .cancel(id: CancelId())
case .setSheet(isPresented: true): case .setSheet(isPresented: true):
state.isActivityIndicatorVisible = true state.isActivityIndicatorVisible = true
return Effect(value: .setSheetIsPresentedDelayCompleted) return Effect(value: .setSheetIsPresentedDelayCompleted)
.delay(for: 1, scheduler: environment.mainQueue) .delay(for: 1, scheduler: environment.mainQueue)
.eraseToEffect() .eraseToEffect()
.cancellable(id: CancelId())
case .setSheet(isPresented: false): case .setSheet(isPresented: false):
state.optionalCounter = nil state.optionalCounter = nil
@@ -93,6 +102,7 @@ struct LoadThenPresentView: View {
) )
} }
.navigationBarTitle("Load and present") .navigationBarTitle("Load and present")
.onDisappear { viewStore.send(.onDisappear) }
} }
} }
} }

View File

@@ -35,17 +35,19 @@ let presentAndLoadReducer =
with: Reducer< with: Reducer<
PresentAndLoadState, PresentAndLoadAction, PresentAndLoadEnvironment PresentAndLoadState, PresentAndLoadAction, PresentAndLoadEnvironment
> { state, action, environment in > { state, action, environment in
struct CancelId: Hashable {}
switch action { switch action {
case .setSheet(isPresented: true): case .setSheet(isPresented: true):
state.isSheetPresented = true state.isSheetPresented = true
return Effect(value: .setSheetIsPresentedDelayCompleted) return Effect(value: .setSheetIsPresentedDelayCompleted)
.delay(for: 1, scheduler: environment.mainQueue) .delay(for: 1, scheduler: environment.mainQueue)
.eraseToEffect() .eraseToEffect()
.cancellable(id: CancelId())
case .setSheet(isPresented: false): case .setSheet(isPresented: false):
state.isSheetPresented = false state.isSheetPresented = false
state.optionalCounter = nil state.optionalCounter = nil
return .none return .cancel(id: CancelId())
case .setSheetIsPresentedDelayCompleted: case .setSheetIsPresentedDelayCompleted:
state.optionalCounter = CounterState() state.optionalCounter = CounterState()

View File

@@ -9,6 +9,7 @@ struct LazyNavigationState: Equatable {
} }
enum LazyNavigationAction: Equatable { enum LazyNavigationAction: Equatable {
case onDisappear
case optionalCounter(CounterAction) case optionalCounter(CounterAction)
case setNavigation(isActive: Bool) case setNavigation(isActive: Bool)
case setNavigationIsActiveDelayCompleted case setNavigationIsActiveDelayCompleted
@@ -30,12 +31,16 @@ let lazyNavigationReducer =
with: Reducer< with: Reducer<
LazyNavigationState, LazyNavigationAction, LazyNavigationEnvironment LazyNavigationState, LazyNavigationAction, LazyNavigationEnvironment
> { state, action, environment in > { state, action, environment in
struct CancelId: Hashable {}
switch action { switch action {
case .onDisappear:
return .cancel(id: CancelId())
case .setNavigation(isActive: true): case .setNavigation(isActive: true):
state.isActivityIndicatorHidden = false state.isActivityIndicatorHidden = false
return Effect(value: .setNavigationIsActiveDelayCompleted) return Effect(value: .setNavigationIsActiveDelayCompleted)
.delay(for: 1, scheduler: environment.mainQueue) .delay(for: 1, scheduler: environment.mainQueue)
.eraseToEffect() .eraseToEffect()
.cancellable(id: CancelId())
case .setNavigation(isActive: false): case .setNavigation(isActive: false):
state.optionalCounter = nil state.optionalCounter = nil
return .none return .none
@@ -120,6 +125,11 @@ class LazyNavigationViewController: UIViewController {
@objc private func loadOptionalCounterTapped() { @objc private func loadOptionalCounterTapped() {
self.viewStore.send(.setNavigation(isActive: true)) self.viewStore.send(.setNavigation(isActive: true))
} }
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.viewStore.send(.onDisappear)
}
} }
struct LazyNavigationViewController_Previews: PreviewProvider { struct LazyNavigationViewController_Previews: PreviewProvider {

View File

@@ -30,16 +30,20 @@ let eagerNavigationReducer =
with: Reducer< with: Reducer<
EagerNavigationState, EagerNavigationAction, EagerNavigationEnvironment EagerNavigationState, EagerNavigationAction, EagerNavigationEnvironment
> { state, action, environment in > { state, action, environment in
struct CancelId: Hashable {}
switch action { switch action {
case .setNavigation(isActive: true): case .setNavigation(isActive: true):
state.isNavigationActive = true state.isNavigationActive = true
return Effect(value: .setNavigationIsActiveDelayCompleted) return Effect(value: .setNavigationIsActiveDelayCompleted)
.delay(for: 1, scheduler: environment.mainQueue) .delay(for: 1, scheduler: environment.mainQueue)
.eraseToEffect() .eraseToEffect()
.cancellable(id: CancelId())
case .setNavigation(isActive: false): case .setNavigation(isActive: false):
state.isNavigationActive = false state.isNavigationActive = false
state.optionalCounter = nil state.optionalCounter = nil
return .none return .cancel(id: CancelId())
case .setNavigationIsActiveDelayCompleted: case .setNavigationIsActiveDelayCompleted:
state.optionalCounter = CounterState() state.optionalCounter = CounterState()
return .none return .none