Replies: 3 comments 6 replies
-
Hi @jgoodrick, regarding this:
That is not correct. There are two I'm not entirely understanding the problems you are having. Are you dealing with a Or if that is not what you are describing then you may need to share some code. Ideally something that is compiling to demonstrate the problem you are trying to solve. |
Beta Was this translation helpful? Give feedback.
-
@jgoodrick correct me if I'm wrong but my understanding is a parent like:
Where the child is:
So we should drive the I think the current solution right now seems to be either of these:
|
Beta Was this translation helpful? Give feedback.
-
Still no solution for this problem? 😭 |
Beta Was this translation helpful? Give feedback.
-
When we have a collection of identified items stored in Shared state, we often want to iterate over those items in the view with a SwiftUI ForEach or List. Using an IdentifiedArray makes this very ergonomic, as it provides a stable index for each element, and we can even use $array.elements to derive an individual Shared to pass to each cell, if we need. This works great for most use cases, and potentially is where this discussion could end.
However, as requested by @stephencelis, I started this discussion in order to potentially understand the problem space a bit better, and to facilitate a more discoverable set of ideas.
Using .forEach to integrate a collection of child stores
So my take on it is that we have a .forEach higher order reducer that looks, at first glance, like exactly what we need to integrate a collection of child features into a parent reducer. However, as I understand it, it was developed primarily to support NavigationStacks which use StackState and StackActions to operate. Shared collections seem to me to be significantly different, conceptually than a NavigationStack's path.
While a path contains a collection of StackStates that can be pushed and popped, as far as I understand it, all elements in the collection are retained for the life of the NavigationStack, whereas with ForEach SwiftUI will do its best to guard memory resources by releasing/reusing views derived from elements that are no longer in view. Feel free to correct me if I'm wrong about any of that.
So while it's perfectly reasonable to design a navigation destination as a Child feature to some parent that owns the Stack, that ParentStore -> (many) ChildStore relationship doesn't quite translate as well to what might be a scrollable list of hundreds or thousands of elements in a List view, for example. However, I'm pretty sure one actually can do this, if the parent state contains an collection of those child states, using the same .forEach reducer, and some kind of corollary to StackState and StackAction (you might be able to use those directly, I'm not sure, I haven't tried it yet).
But it's a significant amount of work to integrate with an indeterminate number of child stores, so it's strongly worth considering if a simple SwiftUI view can achieve the same goals by just injecting the data and closures needed to delegate each cell's logic and effects to the parent entirely, thereby avoiding this whole problem.
Integrating a collection of local states with a collection of @shared states
The whole problem gains another layer of complexity if we want the collection of child features to be based off of a Shared collection of potentially-persistent data. Generally, the state a child feature operates from is not all intended to be persisted or shared with other parts of the application. It often includes what might be termed 'local state' (as opposed to Shared state) with a lifetime that is often tied to the lifetime of the view driven by that store, much like the @State property wrapper in a SwiftUI View and unlike the lifetime of the Shared state which is often intended to be persisted across application launches.
A member of the Slack community, Woody Melling (sorry, couldn't easily find his handle to tag him) seems to have handled this by creating a separate IdentifiedArray of the child state, derived from the Shared collection of source data, and then utilized the source collection's Shared publisher to keep the two in sync. In concept, this solution makes sense to me, but seems like it could be generalized and turned into some kind of helper that would allow you to derive a child's 'combination' state (local + Shared) from each element in an identified Shared collection.
However, I have at least one reservation I after thinking through how I might use it, if such a tool were available:
It would be tempting to reach for Destinations to attach to each child feature, but views like ForEach and List are not intended for that kind of use, and even log warnings when you try to attach a .navigationDestination or .sheet modifier to a view produced by their lazy loading logic.
Conclusion (for now)
So, for now, I'm convinced to stick to vanilla SwiftUI views that delegate all logic and effects to the parent, but I would be very interested if someone in community does end up generalizing a solution that they believe will play nicely with SwiftUI's ForEach and List.
Original Thread:
https://pointfreecommunity.slack.com/archives/C04KQQ7NXHV/p1715819435821909
Beta Was this translation helpful? Give feedback.
All reactions