Dependency vs Part of State #2320
Replies: 5 comments 10 replies
-
Not sure if there's a right or wrong. But my mental model is that all "model" data should live in some form of dependency. Reducers that need this data all do their own observation/requesting of this data when they need it. Sharing data between features using computed properties for child state or manually updating child state from a parent, or monitoring child state from a parent to update itself, is fraught with opportunities to miss propagating one property either way. Can also lead to state inconsistencies. So all data that has a single source of truth lives in dependencies for me. Your |
Beta Was this translation helpful? Give feedback.
-
Shared state is tricky in TCA, but it's because TCA prefers features be built with value types and not reference types. In vanilla SwiftUI you can just pass around reference types all over the place to share state, but that also creates a very complex system that is hard to understand and difficult to test. I will say that all of the new Going back to your concrete situation of needing location in many parts of an app, this definitely should be a dependency. The first style you mention doesn't work well because if you store the current location a single time in your state at the root of the application, there is no easy way to spread it throughout your other features. It requires complex use of computed properties to play changes back and forth between features, and it is easy to get wrong. There was a lot of mention of "source of truth" in the dicsussions above, but that's a too simplistic way of looking at things. In reality, every application actually has two sources of truth, not one. There is the state that powers your view, such as every boolean that controls if something is enabled or not, etc. And then you have state that lives in external systems, such as the file system, user defaults, databases and on external servers. Every application has a mixture of both kinds of state, and both are very different. The current location of the device is not view state. It's external state, and so belongs in a dependency. There are a few ways you can handle this, but here's one that comes to mind. You can model a location dependency like so: struct LocationClient {
var currentLocation: () -> Location?
var trackLocation: () async -> Void
var locationStream: () async -> AsyncStream<Location>
} These 3 endpoints allow you to do the following:
This allows you to share state across the entire type, and continue living in the value type world. Sure it may mean that each feature that needs location data has its own little copy of the current location in its state, and each feature may get actions delivered when the location changes, but that's not really that big of a deal. |
Beta Was this translation helpful? Give feedback.
-
Bingo this was my question on the slack channel. Except for me the external state is a custom database. |
Beta Was this translation helpful? Give feedback.
-
I'm adopting the strategy on WebSocketActor: GlobalActor which is basically wrapping a shared state that helps the client provide the proper answers to independent reducers etc. Many thanks at the guys from pf. |
Beta Was this translation helpful? Give feedback.
-
Yep, same here. If there are some shared state required—I'm creating an actor with some simple observability pattern build on top of continuations. |
Beta Was this translation helpful? Give feedback.
-
Hey folks! I’m stuck trying to understand the mental model behind state and dependency modelling, especially I’m uncertain in how my reducers better gain access to the same data originally coming from external providers at the different levels in a parent-child state tree.
There are some certain scenarios I’m having issues to design.
Let’s say we have an app and many of its features are depending on the current user location. In the simplest scenario all of the app components especially if they are seen by users use the same most relevant instance of location.
2 ways to implement it:
As all of the features depend on the same location provider, there is no reason to have more than one effect in the system that is responsible for retrieving live user location. The result of this effect is the action which is received by the reducer at the very high level of the hierarchy.
Implement LocationProvider dependency which can be then injected to any feature that needs an access to the location.
Final thoughts:
As for me I’ll prefer to deliver location to features via dependency but I’ll appreciate your input on my decision.
Is it bad? Do TCA has any manifesto on how to model your dependencies and where is the border between updatable property on state and dependency.
Beta Was this translation helpful? Give feedback.
All reactions