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")
            }
        }
 
4
Kudos
 
4
Kudos

Now read this

Data Flow Through SwiftUI

This article may be considered a condensed version of the (highly-recommended) WWDC19 talk, “Data Flow Through SwiftUI”, along with a few thoughts and insights of my own. It represents my own, current understanding of data flow in... Continue →