It’s been just under two months since we kicked off our navigation beta, in which we released an assortment of tools to manage presentation in the Composable Architecture. This included tools for dealing with alerts, confirmation dialogs, sheets, popovers, fullscreen covers, pre-iOS 16 navigation links, and the tree-based navigationDestination
view modifier. The beta notably did not provide tools for iOS 16’s NavigationStack
, but that changes today.
Like last time, we’re not going to give a detailed overview of these new tools and how we motivated or designed them (see the forthcoming episodes for that 😉), and documentation is still in-progress, but here is a very quick overview of the stack-based tools and how to use them.
When a root feature contains a navigation stack of elements to be presented, you will enhance its domain using the new
StackState
andStackAction
types:struct Root: ReducerProtocol { struct State { var path = StackState<Child.State>() … } enum Action { case path(StackAction<Child.State, Child.Action>) … } }
StackState
is a collection type that is specialized for navigation operations in the Composable Architecture, where each element represents a screen in the stack that is powered by its own reducer. It is similar to SwiftUI’sNavigationPath
, and has many of the same operations likeappend
andremoveLast
, but it is not type-erased: you can freely inspect and mutate the data inside.Then you will make use of the new, special
forEach
reducer operator that can single out the stack state and action, and run the child feature on that element when it is active:var body: some ReducerProtocolOf<Self> { Reduce { state, action in … } .forEach(\.path, action: /Action.path) { Child() } }
That’s all that is needed as far as the domain and reducer is concerned. The
forEach
operator has been with the library since the beginning, but is now enhanced with super powers, including automatically cancelling child effects when they are dismissed, and more.The last step is in the view, where the library provides a new
NavigationStackStore
view, which powers aNavigationStack
and its destinations using a store.struct RootView: View { let store: StoreOf<Root> var body: some View { NavigationStackStore( store.scope(state: \.path, action: { .path($0) }) ) { Text("Welcome") } destination: { store in ChildView(store: store) } } }
That’s the basics. There’s a whole lot more to learn, but we will leave it at that for now, and we encourage you to explore the updated branch when you get a chance.
These new stack-based tools are already available on the navigation-beta
branch. If you’ve been testing things so far, you can pull the latest and immediately make use of these tools. The 1.0 preview likewise has been updated with the latest, greatest tools. Otherwise, you can update your SPM dependencies to point to the navigation-beta
branch:
.package(
url: "https://github.com/pointfreeco/swift-composable-architecture",
branch: "navigation-beta"
),
We hope these tools fill a gap in the library and make it ready for its first major release.
As always, if you take things for a spin, please let us know (via Twitter, Mastodon, GitHub discussions, or our new Slack community) if you have questions, comments, concerns, or suggestions!