These are the lesson notes for this day. Its build-along tutorial and flash cards have not been written yet.
The environment carries values down the view tree without your handing them through every initializer on the way. A view reads a value with @Environment(\.colorScheme). An ancestor sets a value for everything beneath it with .environment(\.key, value). The system supplies many values this way: the color scheme, the size class, the locale, an action that dismisses the current screen. You add your own with the @Entry macro in an extension of EnvironmentValues. You can also place a whole @Observable object in the environment with .environment(model) and read it with @Environment(Model.self).
Use the environment for things that many views need and few of them change: a theme, a service, the current user. Do not use it to avoid deciding who owns a piece of data. A parameter in an initializer is easier to follow and easier to preview.
extension EnvironmentValues {
@Entry var accent: Color = .orange // a new environment value and its default
}
struct Root: View {
var body: some View {
Detail()
.environment(\.accent, .purple) // set it for everything below
}
}
struct Detail: View {
@Environment(\.accent) private var accent // read it, at any depth
var body: some View {
Text("Hello").foregroundStyle(accent)
}
}
Exercise
Define a custom environment value for an accent color with @Entry. Set it at the root of your app, read it three levels down, and override it for one subtree only.
@Observable object from the environment and no ancestor provided one?