Efectos y dependencias
Gestione efectos secundarios e inyecte dependencias.
Efectos y dependencias es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 4 lecciones en total.
Por qué existen los efectos
Los reducers deben mantenerse puros: dado un estado y una acción, solo modifican el estado. Sin embargo, las aplicaciones reales necesitan efectos secundarios, como solicitudes de red y temporizadores. TCA los modela como Effects que devuelve el reducer, manteniendo pura la mutación mientras el trabajo asíncrono se ejecuta por separado.
Esta separación es lo que hace que las funcionalidades se puedan probar.
import ComposableArchitecture
// Reducer stays pure; side effects are values it returns.
// Returning .none means no further work.Devolver .none
Cuando una acción solo cambia el estado y no necesita trabajo posterior, el reducer devuelve .none. Este es el efecto más habitual e indica que no hay nada asíncrono que hacer.
Ya ha visto este caso; es la opción básica a la que vuelve cada rama.
import ComposableArchitecture
Reduce { state, action in
switch action {
case .incrementTapped:
state.count += 1
return .none
}
}Effect.run para el trabajo asíncrono
Para realizar trabajo asíncrono, devuelva .run. Su cierre recibe un controlador send que se utiliza para devolver los resultados al sistema como acciones nuevas.
Aquí, una acción de obtención carga datos y envía una acción de respuesta cuando termina.
import ComposableArchitecture
Reduce { state, action in
switch action {
case .reloadTapped:
return .run { send in
let value = try await loadNumber()
await send(.responseReceived(value))
}
case let .responseReceived(value):
state.count = value
return .none
}
}Devolver resultados como acciones
Un efecto no puede modificar el estado directamente; en su lugar, envía acciones mediante send. Después, el reducer gestiona esas acciones y actualiza el estado. Este ciclo mantiene todas las mutaciones dentro del reducer.
Así, una respuesta de red se convierte en una acción de respuesta que el reducer almacena.
import ComposableArchitecture
.run { send in
let result = try await fetch()
await send(.dataLoaded(result))
}
// .dataLoaded is then handled by the reducer to set state.Gestionar errores en los efectos
El trabajo asíncrono puede lanzar errores. Puede capturarlos dentro del efecto y enviar una acción de error, lo que permite que el reducer pase limpiamente a un estado de error.
El cierre opcional catch de .run recibe el error lanzado.
import ComposableArchitecture
.run { send in
let value = try await loadNumber()
await send(.responseReceived(value))
} catch: { error, send in
await send(.loadFailed)
}Por qué son importantes las dependencias
Si un reducer llama directamente a un cliente de red o lee la fecha, resulta difícil probarlo y controlarlo. TCA resuelve esto mediante dependencies: servicios inyectables a los que el reducer accede mediante @Dependency.
En las pruebas, puede sustituirlos por simulaciones predecibles.
import ComposableArchitecture
// Instead of calling APIClient.shared directly,
// inject it as a dependency so tests can replace it.El property wrapper @Dependency
Dentro de un reducer, declare una dependencia con @Dependency y asígnele el nombre de su key path en los valores de dependencias. La biblioteca proporciona elementos integrados, como un reloj y un generador de uuid.
Aquí, el reducer incorpora el reloj continuo.
import ComposableArchitecture
@Reducer
struct TimerFeature {
@ObservableState
struct State: Equatable { var seconds = 0 }
enum Action { case start, tick }
@Dependency(\.continuousClock) var clock
var body: some ReducerOf<Self> {
Reduce { state, action in .none }
}
}Usar una dependencia en un efecto
Una vez declarada, use la dependencia dentro de .run. Como el reloj se inyecta, las pruebas pueden proporcionar un reloj de prueba que avance el tiempo cuando se solicite.
Aquí, el temporizador emite un evento cada segundo mediante el reloj inyectado.
import ComposableArchitecture
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .start:
return .run { send in
for await _ in self.clock.timer(interval: .seconds(1)) {
await send(.tick)
}
}
case .tick:
state.seconds += 1
return .none
}
}
}Definir su propia dependencia
Registre dependencias personalizadas haciendo que un valor cumpla DependencyKey y proporcionando un liveValue. Después, añada una propiedad calculada a DependencyValues para que obtenga un key path.
Aquí, un cliente de API se convierte en una dependencia de primera clase.
import ComposableArchitecture
struct NumberClient {
var fetch: () async throws -> Int
}
extension NumberClient: DependencyKey {
static let liveValue = NumberClient {
try await loadNumber()
}
}
extension DependencyValues {
var numberClient: NumberClient {
get { self[NumberClient.self] }
set { self[NumberClient.self] = newValue }
}
}Inyectar la dependencia personalizada
Una vez configurado el key path, el reducer declara el cliente con @Dependency(\.numberClient) y lo llama dentro de los efectos. En producción se usa el valor real; en las pruebas se sustituye.
Aquí, una acción de recarga obtiene los datos mediante el cliente inyectado.
import ComposableArchitecture
@Reducer
struct NumberFeature {
@ObservableState
struct State: Equatable { var value = 0 }
enum Action { case reload, response(Int) }
@Dependency(\.numberClient) var numberClient
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .reload:
return .run { send in
let n = try await numberClient.fetch()
await send(.response(n))
}
case let .response(n):
state.value = n
return .none
}
}
}
}Cancelar efectos
Los efectos de larga duración, como los temporizadores, deben poder cancelarse. Asigne a un efecto un identificador cancellable y cancélelo más adelante desde otra acción con .cancel.
Aquí, el temporizador se puede detener cuando sea necesario.
import ComposableArchitecture
enum CancelID { case timer }
// Start a cancellable effect:
.run { send in /* ... */ }
.cancellable(id: CancelID.timer)
// Stop it from another action:
.cancel(id: CancelID.timer)Comprobación rápida: efectos y resultados
Recuerde cómo un efecto comunica su resultado al reductor.
Resumen: efectos y dependencias
Ha aprendido cómo TCA gestiona los efectos secundarios y la inyección:
- Los reductores se mantienen puros y devuelven valores
Effect;.noneindica que no hay trabajo que realizar. .runejecuta trabajo asíncrono y devuelve los resultados medianteawait send(.action).- Los errores se gestionan con el cierre
catchdel efecto. @Dependencyinyecta servicios como el reloj o sus propios clientes, declarados medianteDependencyKeyyDependencyValues.- Los efectos de larga duración se pueden marcar como
cancellablemediante un identificador.
A continuación compondrá funcionalidades y las probará exhaustivamente.
import ComposableArchitecture
// Recap: pure reducer + Effect.run for async work
// + @Dependency for testable, injectable services.Aprende Swift con un tutor de IA — gratis
Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.
- Cursos
- 122
- Lecciones
- 409
Preguntas frecuentes
¿La lección «Efectos y dependencias» es gratis?
Sí — el texto completo de «Efectos y dependencias» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Efectos y dependencias»?
Gestione efectos secundarios e inyecte dependencias. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Swift Academy?
No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Efectos y dependencias»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Swift Academy?
Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Estado, acción y reductor
- El Store e integración con SwiftUI
- Efectos y dependencias
- Composición y pruebas de funcionalidades