Skip to content

Commit

Permalink
Updates docs for new TCARouter initialiser
Browse files Browse the repository at this point in the history
  • Loading branch information
johnpatrickmorgan committed May 1, 2024
1 parent 7772e25 commit c16291d
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 5 deletions.
90 changes: 87 additions & 3 deletions Docs/Migration/Migrating from 0.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,96 @@ Version 0.9 introduced an API change to bring the library's APIs more in-line wi
2. To enable access to case paths on your coordinator's action type, add the @Reducer macro to your coordinator reducer.
3. Your coordinator's action can be simplified. Instead of the `routeAction` and `updateRoutes` cases, it should have just one case: either `case router(IndexedRouterActionOf<Screen>)` or `case router(IdentifiedRouterActionOf<Screen>)`, where `Screen` is your screen reducer. You will also need to update any references to those cases, e.g. rather than pattern-matching on `case .routeAction(_, let action):` you would pattern-match on `case .router(.routeAction(_, let action)):`, since they are now nested within the `.router(...)` case.
4. Where you previously called `forEachRoute { ... }`, you should now pass a keypath and case path for the relevant parts of your state and action, e.g. `forEachRoute(\.routes, action: \.router) { ... }`.
5. If you were previously using `Effect.routeWithDelaysIfUnsupported(state.routes) { ... }`, you will now need to additionally pass a casepath for the relevant action: e.g. `Effect.routeWithDelaysIfUnsupported(state.routes, action: \.router) { ... }`.
5. Where you previously instantiated a `TCARouter` in your view with the coordinator's entire store, you now scope the store using the same keypath and case path, e.g. `TCARouter(store.scope(state: \.routes, action: \.router)) { ... }`.
6. If you were previously using `Effect.routeWithDelaysIfUnsupported(state.routes) { ... }`, you will now need to additionally pass a casepath for the relevant action: e.g. `Effect.routeWithDelaysIfUnsupported(state.routes, action: \.router) { ... }`.

Here's a full diff for migrating a coordinator:

```diff
struct IndexedCoordinatorView: View {
let store: StoreOf<IndexedCoordinator>

var body: some View {
- TCARouter(store) { screen in
+ TCARouter(store.scope(state: \.routes, action: \.router)) { screen in
SwitchStore(screen) { screen in
switch screen {
case .home:
CaseLet(
\Screen.State.home,
action: Screen.Action.home,
then: HomeView.init
)
case .numbersList:
CaseLet(
\Screen.State.numbersList,
action: Screen.Action.numbersList,
then: NumbersListView.init
)
case .numberDetail:
CaseLet(
\Screen.State.numberDetail,
action: Screen.Action.numberDetail,
then: NumberDetailView.init
)
}
}
}
}
}

+@Reducer
struct IndexedCoordinator {
- struct State: Equatable, IndexedRouterState {
+ struct State: Equatable {
var routes: [Route<Screen.State>]
}

- enum Action: IndexedRouterAction {
+ enum Action {
- case routeAction(Int, action: Screen.Action)
- case updateRoutes([Route<Screen.State>])
+ case router(IndexedRouterActionOf<Screen>)
}

var body: some ReducerOf<Self> {
Reduce<State, Action> { state, action in
switch action {
- case .routeAction(_, .home(.startTapped)):
+ case .router(.routeAction(_, .home(.startTapped))):
state.routes.presentSheet(.numbersList(.init(numbers: Array(0 ..< 4))), embedInNavigationView: true)

- case let .routeAction(_, .numbersList(.numberSelected(number))):
+ case let .router(.routeAction(_, .numbersList(.numberSelected(number)))):
state.routes.push(.numberDetail(.init(number: number)))

- case .routeAction(_, .numberDetail(.goBackTapped)):
+ case .router(.routeAction(_, .numberDetail(.goBackTapped))):
state.routes.goBack()

- case .routeAction(_, .numberDetail(.goBackToRootTapped)):
+ case .router(.routeAction(_, .numberDetail(.goBackToRootTapped))):
- return .routeWithDelaysIfUnsupported(state.routes) {
+ return .routeWithDelaysIfUnsupported(state.routes, action: \.router) {
$0.goBackToRoot()
}

default:
break
}
return .none
}
- .forEachRoute {
+ .forEachRoute(\.routes, action: \.router) {
Screen()
}
}
}
```

## Easy migration

As an alternative to the above, you might prefer to perform a simpler migration in the short-term. If so, you can skip steps 2 and 3 above, and instead manually add a casepath to your coordinator's'action type:
As an alternative to the above, you might prefer to perform a simpler migration in the short-term. If so, you can skip steps 2 and 3 above, and instead manually add a casepath to your coordinator's action type:

```swift
// Quick update for an action that formerly conformed to `IdentifiedRouterAction`.
Expand Down Expand Up @@ -46,4 +131,3 @@ enum Action: CasePathable {
}
}
```

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ struct Coordinator {

### Step 3 - Create a coordinator view

With that in place, a `CoordinatorView` can be created. It will use a `TCARouter`, which translates the array of routes into a nested list of screen views with invisible `NavigationLinks` and presentation calls, all configured with bindings that react appropriately to changes to the routes array. The `TCARouter` takes a closure that can create the view for any screen in the navigation flow. A `SwitchStore` is the natural way to achieve that, with a `CaseLet` for each of the possible screens:
With that in place, a `CoordinatorView` can be created. It will use a `TCARouter`, which translates the array of routes into a nested list of screen views with invisible `NavigationLinks` and presentation calls, all configured with bindings that react appropriately to changes to the routes array. As well as a scoped store, the `TCARouter` takes a closure that can create the view for any screen in the navigation flow. A `SwitchStore` is the natural way to achieve that, with a `CaseLet` for each of the possible screens:

```swift
struct CoordinatorView: View {
let store: StoreOf<Coordinator>

var body: some View {
TCARouter(store) { screen in
TCARouter(store.scope(state: \.routes, action: \.router)) { screen in
SwitchStore(screen) { screen in
switch screen {
case .home:
Expand Down

0 comments on commit c16291d

Please sign in to comment.