Best Practices for State Management in SwiftUI
Written by Team Kodeco
Effective state management is key to building stable and responsive apps in SwiftUI. Below are some best practices for managing state in your SwiftUI apps:
-
Use State and Binding for simple local state.
StateandBindingare perfect for managing simple state that is local to a view or can be passed from a parent view to a child view. Keep in mind that these property wrappers are designed to work with value types. -
Use ObservedObject and Published for complex state. When you have more complex state that can be shared across multiple views, consider using
ObservedObjectandPublishedin combination with a separate state management class. -
Use EnvironmentObject for shared state across unrelated views. If you need to share state across multiple views that aren’t directly related through a parent-child relationship,
EnvironmentObjectcan be a good choice. -
Avoid large State variables. Storing large amounts of data in
Statevariables can lead to performance issues, as SwiftUI recreates your view whenever state changes. - Defer complex computation and side effects. Avoid running complex computations or side effects, like network requests, directly in your view structures.
Let’s illustrate these best practices with an example of a simple task manager app:
class TaskManager: ObservableObject {
@Published var tasks = [String]()
func addTask(_ task: String) {
tasks.append(task)
}
}
struct TaskListView: View {
@EnvironmentObject var taskManager: TaskManager
@State private var newTask = ""
var body: some View {
NavigationStack {
VStack {
TextField("New task", text: $newTask)
.onSubmit {
if !newTask.isEmpty {
taskManager.addTask(newTask)
newTask = ""
}
}
.padding()
List(taskManager.tasks, id: \.self) { task in
Text(task)
}
}
.navigationTitle("Task List")
}
}
}
struct ContentView: View {
@StateObject var taskManager = TaskManager()
var body: some View {
TaskListView()
.environmentObject(taskManager)
}
}
Your preview should look like this:
In this example, you create a TaskManager class that manages a list of tasks. It’s an ObservableObject, which means that SwiftUI will watch for changes to its Published properties and update any views that depend on those properties. The TaskListView uses EnvironmentObject to access the shared TaskManager, and State for the newTask property that’s local to that view. When a new task is committed in the text field, the task is added to the task manager and the text field is cleared.
For more best practices, see the section on “SwiftUI Best Practices & Tips”.