swiftui · note · performance · architecture
Side Effect Boundary Checklist
Context
Side effects usually become messy when they are attached to the wrong trigger.
This checklist helps you decide whether the work belongs in task, onAppear, or onChange.
The snippet
.task(id: searchText) {
await loadResults(for: searchText)
}
.onChange(of: searchText) { _, newValue in
validate(newValue)
}
Why this works
The snippet separates async loading from immediate validation. That keeps the view readable and gives each effect one clear job.
Use this checklist:
- is the effect async and tied to the view’s lifetime?
- should the effect restart when one value changes?
- does the effect need to run only when the view becomes visible?
- can the work be delegated to a model or service instead?
- would a duplicate run cause a bug or just a small inconvenience?
If a duplicate run would be a bug, the effect needs a stronger boundary.
Use it when…
- a screen loads data when a query changes
- a form validates as the user types
- a view should start a cancellable task while it exists
Avoid it when…
- the work is heavy and belongs in a model layer
- the effect is only there because the code was hard to place elsewhere
- the same action would run multiple times without harm and can stay out of the view
Takeaway: The right hook is the one whose trigger matches the work.