Environment: inyección sin cables
Comparte un modelo con todo un árbol de vistas sin pasarlo mano a mano. @Environment inyecta dependencias de forma limpia y desacoplada.
Pasar un modelo de vista en vista mediante parámetros funciona… hasta que tienes cinco niveles de profundidad y cada vista intermedia lo reenvía sin usarlo. El environment resuelve esto: inyectas el modelo una vez y cualquier vista descendiente lo pide directamente.
- El problema del “prop drilling”.
- Inyectar un modelo con
.environment(...). - Leerlo con
@Environment(Modelo.self). - Los valores del environment del sistema.
El problema: pasar a mano
Sin environment, un modelo que necesita una vista profunda tiene que atravesar todas las intermedias:
// tedioso: B y C no usan el modelo, solo lo reenvíanVistaA(modelo: modelo) → VistaB(modelo: modelo) → VistaC(modelo: modelo) → VistaD(modelo: modelo) // la única que lo usaLa solución: inyectar en el environment
Inyectas el modelo en un punto alto del árbol y desaparece de las firmas intermedias:
@mainstruct MiApp: App { @State private var sesion = SesionModel() var body: some Scene { WindowGroup { ContentView() .environment(sesion) // inyectado para TODO el árbol } }}Y cualquier vista descendiente, a cualquier profundidad, lo pide:
struct PerfilView: View { @Environment(SesionModel.self) private var sesion var body: some View { Text("Hola, \(sesion.usuario)") }}Ninguna vista intermedia necesita saber que SesionModel existe. Limpio y desacoplado.
Cuándo environment y cuándo parámetros
Regla práctica: usa parámetros para datos que una vista concreta necesita (el Tarea que muestra una fila), y environment para dependencias transversales que muchas vistas comparten (la sesión, el tema, un router, el modelo de datos global). El environment no es para todo: abusar de él oculta las dependencias y dificulta ver qué necesita cada vista. Para lo compartido de verdad, es perfecto; para lo local, un parámetro explícito es más claro.
Bindings desde el environment
¿Necesitas editar una propiedad del modelo del environment? Reenvuélvelo con @Bindable dentro del body:
struct AjustesView: View { @Environment(AjustesModel.self) private var ajustes var body: some View { @Bindable var ajustes = ajustes // habilita los $bindings Toggle("Notificaciones", isOn: $ajustes.notificaciones) }}Los valores del sistema
El environment ya trae decenas de valores del sistema que puedes leer:
@Environment(\.colorScheme) private var esquema // .light o .dark@Environment(\.dismiss) private var dismiss // cerrar una hoja@Environment(\.locale) private var locale // idioma/región// ejemplo: un botón que cierra la pantalla actualButton("Cerrar") { dismiss() }\.dismiss es especialmente útil: cualquier vista presentada como hoja puede cerrarse a sí misma sin que el padre le pase nada.
Environment values propios
Puedes crear tus propios valores de environment (con @Entry en iOS moderno) para inyectar configuración a medida por todo el árbol. Empieza usando los del sistema y los modelos @Observable; los valores personalizados llegan cuando los necesites.
Inyecta sin cables
- Crea un modelo
@Observable(p. ej.SesionModelcon unusuario). - Inyéctalo en el
WindowGroupcon.environment(...). - Léelo en una vista profunda con
@Environment(SesionModel.self). - En otra vista, usa
@Bindable varlocal para editar una propiedad con unToggle. - Añade un botón “Cerrar” que use
@Environment(\.dismiss).