Creating a list view with sections #907
-
I am just getting started with compositional architecture, so I could be overlooking something that is obvious. I am trying to construct a list that contains sections. For example, if I have a list of categorized products struct CategorizedProducts: Equatable, Identifiable {
let id: UUID
let category: Category
let products: [Product]
} Each section is represented by a category that lists the corresponding products. I have reviewed the todo example app, but this doesn't contain sections. So how would I create a parent reducer and view considering this data model? struct ProductsState: Equatable {
let categorizedProducts: [CategorizedProducts]
}
enum ProductsActions: Equatable {
case product(id: Product.ID, action: ProductAction)
}
struct ProductsEnvironment {}
let productsReducer = Reducer<ProductsState, ProductsActions, ProductsEnvironment>.combine
(
productReducer.forEach(
state: \. ???? // Not sure how to create this,
action: /ProductsActions.product(id:action:),
environment: { _ in ProductsEnvironment() }
),
Reducer { _, action, _ in
switch action {
case .product(id: let id, action: .someButtonTapped):
return .none
}
}
)
struct ProductsView: View {
let store: Store<ProductsState, ProductsActions>
var body: some View {
WithViewStore(self.store) { viewStore in
List {
ForEach(viewStore.state.categorizedProducts) { info in
Section(header: Text(info.category.rawValue)) {
// Not sure how to create the child stores
}
}
}
}
}
}
// Product
struct ProductState: Equatable {}
enum ProductAction: Equatable {
case someButtonTapped
}
struct ProductEnvironment {}
let productReducer = Reducer<ProductsState, ProductAction, ProductEnvironment> { _, action, _ in
switch action {
case .someButtonTapped:
return .none
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
There are several ways to solve your problem, but I would go with the simplest when using TCA: composing features. I would introduce an intermediary "categorized products" feature, with You embed the Each "categorized products" feature is responsible for managing a flat list of Now that you have a "categorized product" feature working, you can embed it in some "Products" feature. In your view, you can replace your The ability to compose domains like this is one of the killer-feature of TCA. Each feature can be considered as a top-level feature, as a whole app by itself. When you develop things in TCA, you tend to think "backward": "How do I embed this feature into another, bigger, one". In your case, this quite naturally leads to embedding "product" into "categorized products", which is the next level of complexity, instead of "products", which force us to go in the other way when going back to "categorized products". There are other solutions of course, and you can drill down to individual products directly from the main "products" feature, but you will have to fight a little with the built-in tools provided by the architecture, or define your owns. Footnotes
|
Beta Was this translation helpful? Give feedback.
There are several ways to solve your problem, but I would go with the simplest when using TCA: composing features.
I would introduce an intermediary "categorized products" feature, with
CategorizedProducts
as a state, aCategorizedProductsAction
, aCategorizedProductsEnvironment
and acategorizedProductsReducer
. You can also define a SwiftUICategorizedProductsView
that presents the flat list of products it contains1.You embed the
productReducer
incategorizedProductsReducer
usingforEach
. Because the "product" feature has no knowledge of its outside world, it doesn't have to change its internals when it is embedded in a "categorized products" feature.Each "categorized products" feature…