You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Today i wanted to have some opinion on two different ways of fetching local data in TCA flows.
By local data, i mean UserDefaults, Database, or anything else.
For the base example, i will take a shopping app : the stored data will be items in the user cart.
Imagine the user can add an item in his cart from many places in the app (from sub-modules).
1 - Included in app flow
The steps are :
In the onAppear action, I will load my data using a classic effect, which will read the data from any local storage ;
I will receive my fetched data in an action like dataFetched(Result<[Cart.Item], Error>) : in here, i will just mutate the state to store those items ;
Every time the items needs to be modified, i will call an effect in the related TCA module, which take in parameter the existing items, and the new one. This effect is responsible to make some checks and then, send back the whole updated items to the system.
// App Reducer
switch action {case.onAppear:return environment.loadData().map(Action.dataFetched)case.dataFetched(.success(let result)):
state.data = result
}
// Sub-module reducer
switch action {case.addItemTapped(let item):return environment.addItem(item, state.items).map(Action.dataUpdated)case.dataUpdated(.success(let result)):
state.data = result // this data is pulledback to App reducer after this
}
Pros :
It seems like a classic way of fetching data, to do it only one time than having a long-living effect for this ;
Cons :
You need to pass along the items through all the modules that can updates the value : which means each of those modules will have a dataUpdated action and will update the state ;
If the data is updated in the local storage from another source, the TCA module will never be aware of it ;
2 - Through a long-living effect
The steps are :
In the onAppear action, i will load my data using a long-living Effect, that can check every update in the local storage then immediately emits a new value, which will be injected in the system ;
Like the first solution, I will receive my fetched data in an action like dataFetched(Result<[Cart.Item], Error>) : in here, i will just mutate the state to store those items ;
Every time the items needs to be modified, i will call an effect in the related TCA module, which take only the new item to add. This effect is just an Effect<Never, Never>, and the updated data will be fetched back using the long-living effect ;
// App Reducer (same as previous example)
switch action {case.onAppear:return environment.loadData().map(Action.dataFetched)case.dataFetched(.success(let result)):
state.data = result
}
// Sub-module reducer
switch action {case.addItemTapped(let item):return environment.addItem(item).fireAndForget() // after that, data will be updated through parent reducer + scope
}
Pros :
The app is notified every time the local storage updates the value ;
Only one source of updating the items in the state ;
Cons :
Can be tricky to handle when updates are finished (or maybe you have to return something else than Effect<Never, Never>) when your update your data ;
If items are updated directly in the state, you can't send the entire value to store it (or you need a dedicated Effect to do so) ;
It can be strange that the data is updated in sub-modules through environment, but always getting back to the system through an action in the main module ;
At this time, and seeing pros and cons, i think the long-living effect solution is a better one.
But i wanted to get some opinions about this, so, be free :-)
If you need a more visual example, i can share an example demo representing the two solutions.
EDIT 18/08 : i've added little code examples for clarity.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello everyone,
Today i wanted to have some opinion on two different ways of fetching local data in TCA flows.
By local data, i mean UserDefaults, Database, or anything else.
For the base example, i will take a shopping app : the stored data will be items in the user cart.
Imagine the user can add an item in his cart from many places in the app (from sub-modules).
1 - Included in app flow
The steps are :
onAppear
action, I will load my data using a classic effect, which will read the data from any local storage ;dataFetched(Result<[Cart.Item], Error>)
: in here, i will just mutate the state to store those items ;Pros :
Cons :
dataUpdated
action and will update the state ;2 - Through a long-living effect
The steps are :
onAppear
action, i will load my data using a long-living Effect, that can check every update in the local storage then immediately emits a new value, which will be injected in the system ;dataFetched(Result<[Cart.Item], Error>)
: in here, i will just mutate the state to store those items ;Effect<Never, Never>
, and the updated data will be fetched back using the long-living effect ;Pros :
Cons :
Effect<Never, Never>
) when your update your data ;At this time, and seeing pros and cons, i think the long-living effect solution is a better one.
But i wanted to get some opinions about this, so, be free :-)
If you need a more visual example, i can share an example demo representing the two solutions.
EDIT 18/08 : i've added little code examples for clarity.
Beta Was this translation helpful? Give feedback.
All reactions