Skip to content

Commit 9e741f5

Browse files
committed
Added better example for cancellable ActionPlan.
1 parent a125921 commit 9e741f5

File tree

2 files changed

+68
-20
lines changed

2 files changed

+68
-20
lines changed

Guides/Getting Started.md

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ SwiftDux helps build SwiftUI-based applications around an [elm-like architecture
1515

1616
The state is an immutable structure acting as the single source of truth within the application.
1717

18-
Below is an example of a todo app's state. It has a root `AppState` as well as an ordered list of `TodoState` objects.
18+
Below is an example of a todo app's state. It has a root `AppState` as well as an ordered list of `TodoItem` objects.
1919

2020
```swift
2121
import SwiftDux
@@ -89,7 +89,7 @@ window.rootViewController = UIHostingController(
8989
## Middleware
9090
SwiftDux supports middleware to extend functionality. The SwiftDuxExtras module provides two built-in middleware to get started:
9191

92-
- `PersistStateMiddleware` Persists and restores the application state between sessions.
92+
- `PersistStateMiddleware` persists and restores the application state between sessions.
9393
- `PrintActionMiddleware` prints out each dispatched action for debugging purposes.
9494

9595
```swift
@@ -213,16 +213,35 @@ struct MyView: View {
213213
}
214214
```
215215

216-
If it's an ActionPlan that's meant to be kept alive through a publisher, then you'll want to send it as a cancellable.
216+
If it's an ActionPlan that's meant to be kept alive through a publisher, then you'll want to send it as a cancellable. The action below subscribes
217+
to the store, so it can keep a list of albums updated when the user applies different queries.
217218

218219
```swift
219-
struct MyView: View {
220+
extension AlbumListAction {
221+
var updateAlbumList: Action {
222+
ActionPlan<AppState> { store in
223+
store
224+
.publish { $0.albumList.query }
225+
.debounce(for: .seconds(1), scheduler: RunLoop.main)
226+
.map { AlbumService.all(query: $0) }
227+
.switchToLatest()
228+
.catch { Just(AlbumListAction.setError($0) }
229+
.map { AlbumListAction.setAlbums($0) }
230+
}
231+
}
232+
}
233+
234+
struct AlbumListContainer: ConnectableView {
220235
@Environment(\.actionDispatcher) private var dispatch
221236
@State private var cancellable: Cancellable? = nil
237+
238+
func map(state: AppState) -> [Album]? {
239+
state.albumList.albums
240+
}
222241

223-
var body: some View {
224-
MyForm.onAppear {
225-
cancellable = dispatch.sendAsCancellable(SecurityAction.whileAccessTokenIsValid)
242+
func body(props: [Album]) -> some View {
243+
AlbumsList(albums: props).onAppear {
244+
cancellable = dispatch.sendAsCancellable(AlbumListAction.updateAlbumList)
226245
}
227246
}
228247
}
@@ -231,9 +250,14 @@ struct MyView: View {
231250
The above can be further simplified by using the built-in `onAppear(dispatch:)` method instead. This method not only dispatches regular actions, but it automatically handles cancellable ones. By default, the action will cancel itself when the view is destroyed.
232251

233252
```swift
234-
struct MyView: View {
235-
var body: some View {
236-
MyForm.onAppear(dispatch: SecurityAction.whileAccessTokenIsValid)
253+
struct AlbumListContainer: ConnectableView {
254+
255+
func map(state: AppState) -> [Album]? {
256+
Props(state.albumList.albums)
257+
}
258+
259+
func body(props: [Album]) -> some View {
260+
AlbumsList(albums: props).onAppear(dispatch: AlbumListAction.updateAlbumList)
237261
}
238262
}
239263
```

README.md

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ SwiftDux helps build SwiftUI-based applications around an [elm-like architecture
5353

5454
The state is an immutable structure acting as the single source of truth within the application.
5555

56-
Below is an example of a todo app's state. It has a root `AppState` as well as an ordered list of `TodoState` objects.
56+
Below is an example of a todo app's state. It has a root `AppState` as well as an ordered list of `TodoItem` objects.
5757

5858
```swift
5959
import SwiftDux
@@ -127,7 +127,7 @@ window.rootViewController = UIHostingController(
127127
## Middleware
128128
SwiftDux supports middleware to extend functionality. The SwiftDuxExtras module provides two built-in middleware to get started:
129129

130-
- `PersistStateMiddleware` Persists and restores the application state between sessions.
130+
- `PersistStateMiddleware` persists and restores the application state between sessions.
131131
- `PrintActionMiddleware` prints out each dispatched action for debugging purposes.
132132

133133
```swift
@@ -251,16 +251,35 @@ struct MyView: View {
251251
}
252252
```
253253

254-
If it's an ActionPlan that's meant to be kept alive through a publisher, then you'll want to send it as a cancellable.
254+
If it's an ActionPlan that's meant to be kept alive through a publisher, then you'll want to send it as a cancellable. The action below subscribes
255+
to the store, so it can keep a list of albums updated when the user applies different queries.
255256

256257
```swift
257-
struct MyView: View {
258+
extension AlbumListAction {
259+
var updateAlbumList: Action {
260+
ActionPlan<AppState> { store in
261+
store
262+
.publish { $0.albumList.query }
263+
.debounce(for: .seconds(1), scheduler: RunLoop.main)
264+
.map { AlbumService.all(query: $0) }
265+
.switchToLatest()
266+
.catch { Just(AlbumListAction.setError($0) }
267+
.map { AlbumListAction.setAlbums($0) }
268+
}
269+
}
270+
}
271+
272+
struct AlbumListContainer: ConnectableView {
258273
@Environment(\.actionDispatcher) private var dispatch
259274
@State private var cancellable: Cancellable? = nil
275+
276+
func map(state: AppState) -> [Album]? {
277+
state.albumList.albums
278+
}
260279

261-
var body: some View {
262-
MyForm.onAppear {
263-
cancellable = dispatch.sendAsCancellable(SecurityAction.whileAccessTokenIsValid)
280+
func body(props: [Album]) -> some View {
281+
AlbumsList(albums: props).onAppear {
282+
cancellable = dispatch.sendAsCancellable(AlbumListAction.updateAlbumList)
264283
}
265284
}
266285
}
@@ -269,9 +288,14 @@ struct MyView: View {
269288
The above can be further simplified by using the built-in `onAppear(dispatch:)` method instead. This method not only dispatches regular actions, but it automatically handles cancellable ones. By default, the action will cancel itself when the view is destroyed.
270289

271290
```swift
272-
struct MyView: View {
273-
var body: some View {
274-
MyForm.onAppear(dispatch: SecurityAction.whileAccessTokenIsValid)
291+
struct AlbumListContainer: ConnectableView {
292+
293+
func map(state: AppState) -> [Album]? {
294+
Props(state.albumList.albums)
295+
}
296+
297+
func body(props: [Album]) -> some View {
298+
AlbumsList(albums: props).onAppear(dispatch: AlbumListAction.updateAlbumList)
275299
}
276300
}
277301
```

0 commit comments

Comments
 (0)