Working with child states without ForEachStore #712
lukeredpath
started this conversation in
Ideas
Replies: 1 comment 2 replies
-
|
I've explored the idea of using a special view instead of a public struct IdentifiableChildStore<ChildState, ChildAction, Content>: View
where ChildState: Identifiable & Equatable, Content: View {
let content: () -> Content
/// Initializes a structure that computes a child view from a store of a single identifiable value and
/// an identified action.
///
/// - Parameters:
/// - store: A store on an identified array of data and an identified action.
/// - content: A function that can generate content given a store of an element.
public init<ChildContent: View>(
_ store: Store<ChildState, (ChildState.ID, ChildAction)>,
@ViewBuilder content: @escaping (Store<ChildState, ChildAction>) -> ChildContent
)
where
Content == WithViewStore<ChildState, (ChildState.ID, ChildAction), ChildContent> {
self.content = {
WithViewStore(store) { viewStore in
content(
store.scope(
state: { $0 },
action: { (viewStore.id, $0) }
)
)
}
}
}
public var body: some View {
self.content()
}
}Compare how they are used: With a collection of identifiable state: ForEachStore(
store.scope(
state: \.customWidgets,
action: WidgetsAction.widget(id:action:)
),
content: { WidgetRowView(store: $0) }
)
}With a single item: IdentifiableChildStore(
store.scope(
state: \.systemWidget,
action: WidgetsAction.widget(id:action:)
),
content: { WidgetRowView(store: $0) }
)
} |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
A common pattern when displaying a collection of states is to have a child view that takes a store of some child state and using it with
ForEachStoreto pull each child state out of a collection on the parent domain. For this to work, it requires that your child view fires actions in the form.child(id:action).Sometimes you might want to use the same child view to display a single record outside the context of a collection. For example, imagine a
Listview with different sections - each section displays the sameChildRowViewbut some sections display aChildRowViewfor a single specificChildwhilst another section iterates over a collection of children usingForEachStore.Currently this is very awkward to achieve because it requires a bit of hoop-jumping to map the child actions back to the parent domain - something you don't need to think about when working with a collection because
ForEachStorehandles this for you.For example, given the following basic domain:
In our view, we can easily iterate over the
customWidgetsand pass the child stores into aWidgetRowView:If we want to display a
WidgetRowViewfor thesystemWidgetwe need to be able to scope the parent store down to a child store for just that one single widget. The state scoping is trivial but the action is a bit awkward:The example above might not look too bad if you already have access to a
ViewStorethat you can easily obtain theidfrom but that might not always be the case - you might not have access to aviewStoreor you might have already scoped the store down from the current view's store (imagine if.systemWidgetwas optional and so you're usingIfLetStoreto get access to a store of some concrete value) so you need to create aViewStoreand pluck the ID out. It's not very obvious or ergonomic.My current solution to make this better is a custom
.scopeoverload that handles this for me.As you can see if this was part of the library, it would be able to just pull the
.idout of the store directly, just like theForEachStoreimplementation does.I've opened this discussion to gauge whether or not there's a desire to incorporate something into TCA that might make this easier, or if there's another good way of approaching this? I'm conscious that too many overloads could be confusing so perhaps if something were to be incorporated into TCA it would be some kind of
Viewthat is likeForEachStorebut for a single item rather than ascopeoverload?Beta Was this translation helpful? Give feedback.
All reactions