Thanks for the feedback @mbrandonw! Sorry for the delay, just getting back to this project now after working on something else. So removing the requirement that the dependency returns a non-nil value, and assuming it's modeled as an optional, I'm still unsure where is the appropriate place to do this using TCA:
In the situation of a user switch or logout I imagine you would recreate the base view of the application. Just seems like a good way to reset everything
Take a simplified version of the TicTacToe example:
public var body: some ReducerProtocol<State, Action> { Reduce { state, action in switch action { case let .login(.loginResponse(.success)) state = .newGame(NewGame.State()) return .none case .login: return .none case .newGame(.logoutButtonTapped): state = .login(Login.State()) return .none case .newGame: return .none } } .ifCaseLet(/State.login, action: /Action.login) { Login() } .ifCaseLet(/State.newGame, action: /Action.newGame) { NewGame() } }
Where would you handle updating the dependency in a case like this? Feels like we'd want to do it when we're changing the state between login and newGame, but we can't update dependencies there. What I'm now doing is something approximately like this:
.ifCaseLet(/State.login, action: /Action.login) { Login() .dependency(\.currentUser, nil) } .ifCaseLet(/State.newGame, action: /Action.newGame) { @Dependency(\.keychain) var keychain NewGame() .dependency(\.currentUser, try? keychain.get(.currentUser))) }
It seems to work, but I'm not sure it's correct. The docs for transformDependency mention this warning:
The trailing closure of transformDependency(_:transform:) is called for every action sent to the reducer, and so you can expect it to be called many times in an application’s lifecycle. This means you should typically not create dependencies in the closure as that will cause a new dependency to be created everytime an action is sent.
I noticed the code above behaves the same, Login() and NewGame() reducers are recreated on every single action sent in the app, recreating both their dependencies every time, so I feel like I'm missing something about the right way to approach this.