Based on the responses in this post I've implemented shared state like this:
struct AppState: Equatable {
var value: Value
var homeState = HomeState()
var homeValueState: SharedValueState<HomeState> {
get {
SharedValueState(value: value, state: homeState)
}
set {
value = newValue.value
homeState = newValue.state
}
}
}
struct HomeState: Equatable {
var error: Error?
}
@dynamicMemberLookup
struct SharedValueState<State: Equatable>: Equatable {
var value: Value
var state: State
subscript<LocalState>(dynamicMember keyPath: WritableKeyPath<State, LocalState>) -> LocalState {
get { self.state[keyPath: keyPath] }
set { self.state[keyPath: keyPath] = newValue }
}
}
The Home reducer is of type Reducer<SharedGoalState<HomeState>, HomeAction, HomeEnvironment>
and can operate on state.goal
since the state is @dynamicMemberLookup
.
Then the store in my view is var store: Store<SharedValueState<HomeState>, HomeAction>
With this, the source of truth for the Value
instance is always the value
member on AppState
.