Sure...
You have two separate contexts happening here. In your original question, in the first code snippet you ask 👇[🤨: Is this how scope is done in SwiftUI?].
But... this is not SwiftUI code. This is just Swift. It might LOOK a bit like SwiftUI but that's because it's built using a ResultBuilder. A deep dive into Swift’s result builders | Swift by Sundell
Reducer
So... in this code...
struct ProductDomain: ReducerProtocol {
struct State: Equatable {
var addToCartDomainState: AddToCartDomain.State
}
enum Action {
case addToCartDomain(AddToCartDomain.Action)
}
var body: some ReducerProtocol<State, Action> {
Scope(
state: \.addToCartDomainState,
action: /Action.addToCartDomain
) {
AddToCartDomain()
}
}
}
This is NOT SwiftUI. This is your Reducer. Just written in Swift. There is no UI here. This Reducer called ProductDomain deals with two types.
-
ProductDomain.State the data part of your reducer
-
ProductDomain.Action the actions that the reducer can process
BUT...
You have another reducer AddToCartDomain and you need one of these for your other view and your other data and actions.
So we need to get from a reducer of ProductDomain.State and ProductDomain.Action and somehow change this into a reducer of AddToCartDomain.State and AddToCartDomain.Action. To do this... we can Scope it.
So in your code you are passing into it the instructions of how to get from ProductDomain to AddToCartDomain.
- You get from
ProductDomain.State to AddToCartDomain.State by doing this... \.addToCartDomainState
- You get from
ProductDomain.Action to AddToCartDomain.Action by doing this... ProductDomain.Action.addToCartDomain
View
In this code...
struct ProductCard: View {
let store: StoreOf<ProductDomain>
var body: some View {
WithViewStore(store, observe: { $0 }, content: { viewStore in
HStack(alignment: .center) {
AddToCart( 👇
store: store.scope(
state: \.addToCartDomainState,
action: ProductDomain.Action.addToCartDomain
)
)
}
}
}
}
Now you are in the view and this IS SwiftUI. So we have a view that takes a StoreOf<ProductDomain>. BUT we get to a bit further down where we want to display a AddToCart view and that takes a StoreOf<AddToCartDomain. So again... we need to tell the view how to get from StoreOf<ProductDomain> to StoreOf<AddToCartDomain>. How do we do this?
Well, now we can scope the store.
store.scope(
state: \.addToCartDomainState,
action: ProductDomain.Action.addToCartDomain
)
This is telling the view how to take one store and scope it to another store.
Summary
For each "scope" you will normally need two parts to match up.
- The
Reducer is scoped using a Scope(.......) in the reducer body.
- The
Store is scoped by using store.scope(......) in the view body.
In most basic cases these will look very similar.