NEW BOOK! The SwiftUI Way: A field guide to SwiftUI patterns and anti-patterns. Learn more ...NEW BOOK! The SwiftUI Way:Avoid common SwiftUI pitfalls. Learn more...
Quick Tip

Use onChange() modifier with computed properties

We often use onChange() modifier in SwiftUI to react to environment or state changes, but it can be used with any properties that have Equatable value, even a computed property.

If we need to perform an action when either of multiple properties changes, then it's simpler to make a computed property, rather than add multiple onChange() modifiers for each of them.

Let's say we have a view to set an alarm with a DatePicker and an activation Toggle. When user activates the toggle we set an alarm for selected date. When user changes the date, we cancel the previous alarm if it hasn't been canceled yet and set a new one. When user deactivates the toggle, we cancel the alarm.

In our case we depend on changes in the DatePicker and the Toggle. We could set up two onChange() modifiers to react to changes in each of them. But we could also define an intermediary computed property that will only return a date if alarm is activated and otherwise return nil. Then we can react to changes in that computed date.

struct AlarmView: View {
    @State private var date = Date()
    @State private var isOn = false
    
    var alarmDate: Date? {
        isOn ? date : nil
    }
    
    var body: some View {
        VStack {
            DatePicker(
                "Alarm Time", selection: $date,
                displayedComponents: [.hourAndMinute]
            )
            Toggle("Activate", isOn: $isOn)
        }
        .onChange(of: alarmDate) { oldDate, newDate in
            if oldDate != nil {
                AlartScheduler.cancelAlarm()
            }
            if let date = newDate {
                AlartScheduler.setNewAlarm(for: date)
            }
        }
    }
}

struct AlartScheduler {
    static func cancelAlarm() {
        // cancel alarm here
        print("Cancelling old alarm...")
    }
    
    static func setNewAlarm(for date: Date) {
        // set new alarm here
        print("Setting alarm for: \(date)")
    }
}


If you are looking to build a strong foundation in SwiftUI, my book SwiftUI Fundamentals takes a deep dive into the framework's core principles and APIs to help you understand how it works under the hood and how to use it effectively in your projects. And my new book The SwiftUI Way helps you adopt recommended patterns, avoid common pitfalls, and use SwiftUI's native tools appropriately to work with the framework rather than against it.

For more resources on Swift and SwiftUI, check out my other books and book bundles.

The SwiftUI Way by Natalia Panferova book coverThe SwiftUI Way by Natalia Panferova book cover

Work with SwiftUI. Not against it.$35

A field guide to SwiftUI patterns and anti-patterns

The SwiftUI Wayby Natalia Panferova

  • Avoid common SwiftUI pitfalls
  • Build deeper intuition for the framework
  • Gain insights from a former SwiftUI Engineer at Apple

Work with SwiftUI. Not against it.

A field guide to SwiftUI patterns and anti-patterns

The SwiftUI Way by Natalia Panferova book coverThe SwiftUI Way by Natalia Panferova book cover

The SwiftUI Way

by Natalia Panferova

$35