Inlining @Environment access in SwiftUI
The @Environment
modifier in SwiftUI is a core data-flow primitive, that allows one to access environment values set by the parent.
Example usage:
struct Foo: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
Group {
if colorScheme == .light {
Text("Light")
} else {
Text("Dark")
}
}
}
}
This is all well and good - but note that @Environment
is implemented as a property wrapper and cannot be used without a housing View
structure.
In prototyping code heavily reliant on @Environment
, this can feel cumbersome and boilerplate-y. Hence, I wrote a simple generic wrapper to solve this problem:
public struct EnvironmentValueAccessView<EnvironmentValue, Content: View>: View {
private let keyPath: KeyPath<EnvironmentValues, EnvironmentValue>
private let content: (EnvironmentValue) -> Content
@Environment var environmentValue: EnvironmentValue
public init(
_ keyPath: KeyPath<EnvironmentValues, EnvironmentValue>,
@ViewBuilder content: @escaping (EnvironmentValue) -> Content
) {
self.keyPath = keyPath
self.content = content
self._environmentValue = .init(keyPath)
}
public var body: some View {
content(environmentValue)
}
}
With EnvironmentValueAccessView
now, we can express our example code as a simple inline expression:
EnvironmentValueAccessView(\.colorScheme) { colorScheme in
if colorScheme == .light {
Text("Light")
} else {
Text("Dark")
}
}