Hello everyone,
I've got a question regarding the scoping in stores. I've noticed that the mapping code (view computed var) between state & view state get called a lot with the same value.
For instance, in the TicTacToe sample application, if I add a print in the TwoFactorState mapping like so :
extension TwoFactorState {
var view: TwoFactorViewController.ViewState {
print("Mapping to viewState : \(self)")
return .init(
alert: self.alert,
code: self.code,
isActivityIndicatorHidden: !self.isTwoFactorRequestInFlight,
isLoginButtonEnabled: self.isFormValid && !self.isTwoFactorRequestInFlight
)
}
}
I get the following 6 lines in console output each time I enter a number in the code field (here I entered 1):
Mapping to viewState : TwoFactorState(alert: nil, code: "1", isFormValid: false, isTwoFactorRequestInFlight: false, token: "deadbeef")
Mapping to viewState : TwoFactorState(alert: nil, code: "1", isFormValid: false, isTwoFactorRequestInFlight: false, token: "deadbeef")
Mapping to viewState : TwoFactorState(alert: nil, code: "1", isFormValid: false, isTwoFactorRequestInFlight: false, token: "deadbeef")
Mapping to viewState : TwoFactorState(alert: nil, code: "1", isFormValid: false, isTwoFactorRequestInFlight: false, token: "deadbeef")
Mapping to viewState : TwoFactorState(alert: nil, code: "1", isFormValid: false, isTwoFactorRequestInFlight: false, token: "deadbeef")
Mapping to viewState : TwoFactorState(alert: nil, code: "1", isFormValid: false, isTwoFactorRequestInFlight: false, token: "deadbeef")
I'm a bit afraid that for some less trivial examples with deep nested states, this could impact performance. Also I know it's one of the purposes of ViewStore to filter duplicates, but I'm wondering if it would be a good idea to add a scope method to Store that takes into account the fact that most states are equatable like so :
public func scope<LocalState: Equatable, LocalAction>(
state toLocalState: @escaping (State) -> LocalState,
action fromLocalAction: @escaping (LocalAction) -> Action
) -> Store<LocalState, LocalAction> {
let localStore = Store<LocalState, LocalAction>(
initialState: toLocalState(self.state.value),
reducer: { localState, localAction in
self.send(fromLocalAction(localAction))
localState = toLocalState(self.state.value)
return .none
}
)
localStore.parentCancellable = self.state
.sink { [weak localStore] newValue in
print("Optimized scoping")
let newState = toLocalState(newValue)
guard newState != localStore?.state.value else {
print("Duplicate")
return
}
localStore?.state.value = newState
}
return localStore
}
This way we would avoid spreading the same value to the sub-stores multiple times.
I would love to know your point of view on this ![]()
Thanks for reading !