Efeitos e Dependências
Lide com efeitos colaterais e injete dependências.
Efeitos e Dependências é uma aula grátis de Swift Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Swift Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Swift Academy inclui 4 aulas no total.
Por que existem efeitos
Os redutores devem permanecer puros: dado um estado e uma ação, eles apenas alteram o estado. Mas aplicativos reais precisam de efeitos colaterais, como solicitações de rede e temporizadores. O TCA modela isso como efeitos que o redutor retorna, mantendo a alteração pura enquanto o trabalho assíncrono é executado separadamente.
Essa separação é o que torna as funcionalidades testáveis.
import ComposableArchitecture
// Reducer stays pure; side effects are values it returns.
// Returning .none means no further work.Retornando .none
Quando uma ação apenas altera o estado e não precisa de trabalho posterior, o redutor retorna .none. Esse é o efeito mais comum e sinaliza que não há nada assíncrono a fazer.
Você já viu isso; é a base à qual todo ramo recorre.
import ComposableArchitecture
Reduce { state, action in
switch action {
case .incrementTapped:
state.count += 1
return .none
}
}Effect.run para trabalho assíncrono
Para realizar trabalho assíncrono, você retorna .run. O fechamento recebe um identificador send que você usa para enviar resultados de volta ao sistema como novas ações.
Aqui, uma ação fetch carrega dados e envia uma ação de resposta quando 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
}
}Enviando resultados de volta como ações
Um efeito não pode alterar o estado diretamente; em vez disso, envia ações por meio de send. O redutor então trata essas ações e atualiza o estado. Esse ciclo mantém cada alteração dentro do redutor.
Assim, uma resposta de rede se torna uma ação de resposta que o redutor armazena.
import ComposableArchitecture
.run { send in
let result = try await fetch()
await send(.dataLoaded(result))
}
// .dataLoaded is then handled by the reducer to set state.Tratando erros em efeitos
O trabalho assíncrono pode lançar uma exceção. Você pode capturar erros dentro do efeito e enviar uma ação de falha, permitindo que o redutor passe para um estado de erro de maneira organizada.
O fechamento catch opcional de .run recebe o erro lançado.
import ComposableArchitecture
.run { send in
let value = try await loadNumber()
await send(.responseReceived(value))
} catch: { error, send in
await send(.loadFailed)
}Por que as dependências são importantes
Se um redutor chama um cliente de rede ou lê a data diretamente, fica difícil testá-lo e controlá-lo. O TCA resolve isso com dependências: serviços injetáveis que o redutor acessa por meio de @Dependency.
Nos testes, você as substitui por implementações falsas previsíveis.
import ComposableArchitecture
// Instead of calling APIClient.shared directly,
// inject it as a dependency so tests can replace it.O encapsulador de propriedade @Dependency
Dentro de um redutor, você declara uma dependência com @Dependency, nomeando-a pelo seu caminho de chave nos valores de dependência. A biblioteca fornece itens integrados, como um relógio e um gerador de UUID.
Aqui, o redutor obtém o relógio contínuo.
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 }
}
}Usando uma dependência em um efeito
Depois de declarada, você usa a dependência dentro de .run. Como o relógio é injetado, os testes podem fornecer um relógio de teste que avança o tempo sob demanda.
Aqui, o temporizador marca a passagem de um segundo em um segundo usando o relógio injetado.
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
}
}
}Definindo sua própria dependência
Você registra dependências personalizadas fazendo um valor estar em conformidade com DependencyKey e fornecendo um liveValue. Em seguida, adiciona uma propriedade computada a DependencyValues para que ela receba um caminho de chave.
Aqui, um cliente de API se torna uma dependência de primeira classe.
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 }
}
}Injetando a dependência personalizada
Com o caminho de chave configurado, o redutor declara o cliente com @Dependency(\.numberClient) e o chama dentro dos efeitos. Em produção, usa-se o valor em produção; nos testes, ele é substituído.
Aqui, uma ação de recarregamento busca dados por meio do cliente injetado.
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
}
}
}
}Cancelamento de efeitos
Efeitos de longa duração, como temporizadores, devem poder ser cancelados. Você marca um efeito com um identificador cancellable e o cancela mais tarde a partir de outra ação com .cancel.
Aqui, o temporizador pode ser interrompido sob demanda.
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)Verificação rápida: efeitos e resultados
Relembre como um efeito comunica seu resultado de volta ao redutor.
Recapitulação: efeitos e dependências
Você aprendeu como o TCA lida com efeitos colaterais e injeção:
- Os redutores permanecem puros e retornam valores
Effect;.nonesignifica que não há trabalho a fazer. .runexecuta trabalho assíncrono e devolve results por meio deawait send(.action).- Os erros são tratados com o fechamento
catchdo efeito. @Dependencyinjeta serviços, como o relógio ou seus próprios clientes, declarados por meio deDependencyKeyeDependencyValues.- Efeitos de longa duração podem se tornar
cancellablepor identificador.
A seguir, você combinará funcionalidades e as testará exaustivamente.
import ComposableArchitecture
// Recap: pure reducer + Effect.run for async work
// + @Dependency for testable, injectable services.Aprenda Swift com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 122
- Aulas
- 409
Perguntas Frequentes
A aula “Efeitos e Dependências” é grátis?
Sim — o texto completo de “Efeitos e Dependências” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Swift Academy, atualize para CoddyKit PRO. O curso de Swift Academy inclui 4 aulas no total.
O que vou aprender em “Efeitos e Dependências”?
Lide com efeitos colaterais e injete dependências. Você pratica Swift Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Swift Academy?
Nenhuma experiência prévia é necessária. Swift Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Efeitos e Dependências”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Swift Academy?
Sim. Cada aula de Swift Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Estado, Ação e Redutor
- A Store e a Integração com SwiftUI
- Efeitos e Dependências
- Composição e Teste de Funcionalidades