There are two ways we show how to share state in the case studies:
First, the case study you found shows that you can share state from a parent to a child via an explicit computed property. Maybe the case study doesn't properly explain the technique, but it does apply to your situation. You just need a way to hold both the core feature state and the shared state together, either as a new type or as a tuple:
struct AppState {
var user: User
var screenA: ScreenAState
var screenB: ScreenBState
var featureAState: (user: User, screen: ScreenA) {
get { (self.user, self.screenA) }
set { self.user = newValue.user; self.screenA = newValue.screen }
}
var featureBState: ...
}
struct ScreenAState {
// no User field here
var something = false
}
And then your reducer would operate on (user: User, screen: ScreenA)
instead of just ScreenA
, and your reducer would be pulled back along the \.featureAState
key path instead of the \.screenA
key path. You could also use a typealias or a new struct to wrap that data if that feels better. If you use a struct you could even add @dynamicMemberLookup
to make accessing ScreenA
s data inside the struct nicer.
You could go even further and just have a fully generic base state struct of everything you want shared:
@dynamicMemberLookup
struct BaseState<State> {
var user: User
var state: State
subscript(...) { ... }
}
And that would allow you to share some state with basically every part of your app.
We actually have a case study that does exactly this, except for dependencies and the Environment
. This shows how to create a SystemEnvironment
that wraps another environment and will give all reducers access to a base set of dependencies.
Hopefully that is helpful!