Set currentUser dependency value for child reducer #2825
-
Dearest community. I'm trying to integrate a With my basic understanding of Dependencies my first idea was to have a enum UserState {
case unknown
case guest
case authenticated(Login)
}
extension UserState: DependencyKey {
static let liveValue: UserState = .unknown
}
extension DependencyValues {
var currentUser: UserState {
get { self[UserState.self] }
set { self[UserState.self] = newValue }
}
} and then use this dependency within my api client dependency to set authorization header value. mutating func prepareHeaders(for endpoint: Endpoint) throws {
setValue("application/json", forHTTPHeaderField: "Content-Type")
setValue("application/json", forHTTPHeaderField: "Accept")
if endpoint.requiresAuthentication {
@Dependency(\.currentUser) var currentUser
guard case .authenticated(let login) = currentUser else {
throw URLSessionError.authentication
}
setValue("\(login.tokenType) \(login.accessToken)", forHTTPHeaderField: "Authorization")
}
} In the extension Root {
@Reducer
enum Destination {
case authentication(Authentication)
case home(Home)
}
}
// Root action
case .loginResult(.success(let login)):
state.destination = .home(Home.State())
return .none
// Root View
struct RootView: View {
@Bindable var store: StoreOf<Root>
var body: some View {
ZStack {
Color.systemBackground
.ignoresSafeArea()
if let store = store.scope(
state: \.destination?.authentication,
action: \.destination.authentication
) {
AuthenticationView(store: store)
} else if let store = store.scope(
state: \.destination?.home,
action: \.destination.home
) {
HomeView(store: store)
}
}
.onAppear {
store.send(.onAppear)
}
}
} Is it possible to override the dependency values for the child // Root action
case .loginResult(.success(let login)):
// Override current user dependency for Home reducer
... withDependencies { values in
values.currentUser = .authenticated(login)
}
return .none I'd love to hear suggestions of other patterns of integrating a |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
|
Beta Was this translation helpful? Give feedback.
-
Hi @shredlocker, your dependency can hold onto mutable data and you can mutate it though a dependency endpoint. This is how we handle things in the The I think that is typically a better approach than |
Beta Was this translation helpful? Give feedback.
-
@mbrandonw Thank you for your answer Handling mutable data through a dependency endpoint introduces significant complexity. Let me provide a more detailed example: I have a client that uses a public struct MediaClient: Sendable {
public var getSourceInfo: () async throws -> SourceInfo
public var getChannelCategories: () async throws -> [Category]
public var getMoviesCategories: () async throws -> [Category]
public var getShowsCategories: () async throws -> [Category]
public var getChannels: (Category.ID) async throws -> [Channel]
public var getMovies: (Category.ID) async throws -> [Movie]
public var getShows: (Category.ID) async throws -> [Show]
...
} The public var source: Source?
public var loadSource: (Source) -> Void Both approaches present challenges:
Additionally, some initialization tasks, such as setting up a database, depend on properties when the client is first created. I experimented with Given these considerations, what do you think would be the best approach to solve this issue? Thanks, |
Beta Was this translation helpful? Give feedback.
Hi @shredlocker, your dependency can hold onto mutable data and you can mutate it though a dependency endpoint. This is how we handle things in the
APIClient
in isowords:https://github.com/pointfreeco/isowords/blob/595afc1a425e490f078a7b6e1d4ce6e6f28a56b6/Sources/ApiClient/Client.swift#L7-L15
The
authenticate
endpoint mutates some internal data to represent the current user, andlogout
clears out that data.I think that is typically a better approach than
ReducerReader
.