Working with a common state throughout the app #1898
Replies: 7 comments 18 replies
-
hi @Paul-Svetlichny , have you had a chance to check out the video series tour available for this framework? they break down how to work with the framework from first principals and Swift programming know-how. there are also case studies that show end-to-end how to do a few of the things you asked here. hope that helps! |
Beta Was this translation helpful? Give feedback.
-
Hey @Paul-Svetlichny When you have some internal properties that you want to preserve, one solution is to use some private storage that you use to persist the data. For example if your struct Profile.State {
var score: Int
var currentPage: Int
} you can "save" the struct Parent.State {
var score: Int
private var _profile: Profile.State = .init(score: 0, currentPage: 0)
var profile: Profile.State {
get {
var state = self._profile
profile.score = self.score
return state // A `Profile.State` with an updated `score`.
}
set {
self._profile = newValue // "Save" the current `Profile.State` value
self.score = newValue.score // Propagate the updated `score` to the parent.
}
}
} From your reducer/store, you interact only with About your last question, I'm not 100% sure to follow, but if it boils down to "should this be put in TCA or in SwiftUI", I'm usually using testability to decide: if this is something that I may want to write a test for, it should probably go in TCA. Otherwise, it can go in SwiftUI. In your example, if you want to store the I hope it helps. Feel free to let me know if something was not clear. |
Beta Was this translation helpful? Give feedback.
-
Everything @tgrapperon mentioned above is correct and worth considering, but I just want to add one more clarification about "shared state." Our shared state case study is really only meant for a specific kind of shared state, and that is the kind that does not travel very far. It does handle the situations you asked about (child updating parent, parent updating child, etc.), but because of the boilerplate involved it's really only appropriate if you need to share a small bit of state with a small number of views. For shared state that is ubiquitous and should be available in every corner of the app you need different techniques. Such shared state is really not even distinguishable from user defaults, or data on the disk, or data in a database. As such, it's appropriate to treat that kind of "shared" state as a dependency. It can be a simple client that exposes some properties for reading/writing data to the shared state, and it can expose endpoints for subscribing to state changes (done via effects). Under the hood it can persist the data however it sees fit, e.g. user defaults, saving to disk, saving to SQLite, etc. |
Beta Was this translation helpful? Give feedback.
-
I will update my post a bit with what we've ended up with. It is a bit different (in terms of exact task) from how the topic started, because we've managed to avoid sharing that property so far, but we've encountered another related case and below is how we've managed to implement it so far.
Also the container view itself uses the store the same way:
I'm not sure if this is the correct way of handling the situation, but it works so far and without a boilerplate code. Moreover we have several views depending on that |
Beta Was this translation helpful? Give feedback.
-
Just to add to what has been said before. For me, this was one of the biggest "lightbulb" moments in thinking about and using TCA. I was struggling for a while to work out where all our app's data should live. Like where should the When we chnaged over to treating this shared data as a dependency it suddenly made thinking about TCA much easier. |
Beta Was this translation helpful? Give feedback.
-
I've taken the
The
And
|
Beta Was this translation helpful? Give feedback.
-
@mbrandonw Does it makes sense to use TCA inside of a dependency so that we can use a reducer and test the logic of that dependency easily? or is that an anti-pattern? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hey guys! I've read a lot of articles and seen (and partially adapted into my test project) the Shared State example, but still can't wrap the concept around my head.
In our application we have a lot of properties, which needs to be stored and updated during the whole application lifecycle from external repositories based on different actions in the app.
For simplicity, let's say we have a
score
property in the Main App state.So we have it like this
What it does, it just imitates score update from external repository by randomly updating score as soon as application is launched.
And we have a Profile screen, which shows the score along with other user data, so for now it looks like this (user data is ignored):
So there are a couple of questions finally :)
First of all, as far as I understand, each time the main app state is updated, all the child states, including
Profile.State
in the example above, will be recreated with default values and thenProfile.State
will be updated based on getter. In that case, how to maintain local child state properties?For example, we have
score
as a property, which was stored in the main app state, but we want to add local properties to Profile state, which will be held only there and not synced to the main state, something that is View-dependant and only reflects user interactions. Like if we have paging on the Profile screen and a propertycurrentPage
, which tracks current user progress on that screen, but doesn't need to be stored globally.How to add that property to "local" child state and maintain it when the global state is changed and child state is recreated?
Another related question is what is the best way to update that parent state from the child one, for example, we have user data (mentioned above but not in the code example), which is part of the parent state and is passed to the child state. If it is modified in the child view (e.g. Profile), how to correctly update this data in the parent state?
And finally (for now 😄) how to handle internal interactions, when there is a property to trigger animation and a button, which triggers that property. What is the proper way of handling this? Should we put this property into a state and update it with action? Or can we use an action to update that property without being part of the state?
I know these questions are noobs' ones, but I'm reading documentation and looking at different example for the last several days, and still can't wrap it up. I will really appreciate your help!
Have a great day!
Beta Was this translation helpful? Give feedback.
All reactions