'SwiftUI/Combine: subscribe to value change of @Binding
I have a view with a view model, and actions in this view can change the view model. To be able to break out logic into reusable pieces, I have part of the view as its own view, with a @Binding to the values it needs to have. Now, I want to be able to perform some logic based on the value changes, not necessarily only view changes. How can I do that? If it was a regular property, I'd implement a didSet, but that gets me nowhere. I wanted to use Combine to and treat the @Binding as a publisher, but I couldn't find a way to do that either. Suggestions?
Here's the code:
class ViewModel: ObservableObject {
@Published var counter: Int = 0
}
struct Greeter: View {
@Binding var counter: Int {
didSet {
// this isn't printed....
print("Did set -> \(counter)")
}
}
init(counter: Binding<Int>) {
self._counter = counter
// ...so how about setting up a subscription to the @Binding counter above here?
}
var body: some View {
Text("Hello, world #\(counter)!")
.padding()
}
}
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Greeter(counter: $viewModel.counter)
Button("Go!") {
viewModel.counter += 1
}
}
}
}
So I want to retain the structure where the data is in a ViewModel, and that only parts of it is being passed down to the subview. And it is in the subview (Greeter) I want to be able to do something (let's say print the value like in the didSet)
Solution 1:[1]
Here is possible approach. Tested with Xcode 11.4 / iOS 13.4 (SwiftUI 1.0+)
struct Greeter: View {
@Binding var counter: Int
var body: some View {
Text("Hello, world #\(counter)!")
.padding()
.onReceive(Just(counter)) { // << subscribe
print(">> greeter: \($0)") // << use !!
}
}
}
Note for SwiftUI 2.0+: you can use .onChange(of: counter) {
instead (which is actually built-in replacement for above)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |