Recursive navigation

Could anyone advise how to implement a navigation stack where screens are referencing each other?

For example something like an App Store that has the following screens & transitions:

  1. A list of apps allows navigating to an app view.
  2. The app view allows navigating to a list of similar apps.

As we have a requirement of UI state to be represented in data, there is a problem there. States referencing each other, as a result, the app state structure has an undefined size.

The situation becomes even more problematic if we would try to modularize the app by moving each screen into its own library and try to isolate screens from each other to enable parallel compilation.

1 Like

@Nikita_Leonov I think the recursive higher-order reducer demo may have what you're looking for. It's a simplistic example but demonstrates a recursive navigation tree.

2 Likes

:+1: I should pull the project more often, have not seen this one. Indeed this is in line with a problem we have. I still not quite sure the modularization will be solved with this. The higher-order example has a self-referenced recursive state and do not bring any additional states and do not have modularization constraint at all. Meanwhile in the original provide example has two screens referencing each other. I will need to dig more into the example and try to re-purpose it for the scenario provided. Thanks!

If the state and actions need to be nested recursively, I think you should be able to introduce generic "holes" in a feature that embeds a feature from another module:

struct ModuleState<ExternalState> {
  ...
  var externalState: ExternalState
}

enum ModuleAction<ExternalAction> {
  ...
  case externalAction(ExternalAction)
}

struct ModuleEnvironment<ExternalEnvironment> {
  ...
  var externalEnvironment: ExternalEnvironment
}

You'll have to decide on the trade-off between abstracting over features in this way or merely combining things into a single module.

If the state and actions of features are completely independent, you can pull them back to another module that coordinates everything in a parent state, action, environment, and view.

2 Likes

Another way of doing this is just using explicit types for holding navigation state of particular screen:

struct AState {
  indirect enum Route {
    case b(BState)
    // Other possible routes from screen A
  }
  // ....
  var route: Route?
}

struct BState {
  indirect enum Route {
    case a(AState)
    // Other possible routes from screen B
  }
  // ....
  var route: Route?
}

The same idea applies to Actions as well.

Terms of Service

Privacy Policy

Cookie Policy