This is my code and "print("run to onReceive (text)")" run twice when text change (like a image). Why? and thank you!
import SwiftUI
class ContentViewViewModel : ObservableObject {
@Published var text = ""
}
struct ContentView: View {
@StateObject private var viewModel = ContentViewViewModel()
var body: some View {
ZStack {
TextField("pla", text: $viewModel.text)
.padding()
}
.onReceive(viewModel.$text) { text in
print("run to onReceive \(text)")
}
}
}
CodePudding user response:
Because you have a @Published
variable inside the @StateObject
of your view, the changes in that variable will automatically update the view.
If you add the .onReceive()
method, you will:
- update the view because you have the
@Published
var - update it again when the
.onReceive()
method listens to the change
Just delete the .onReceive()
completely and it will work:
class ContentViewViewModel : ObservableObject {
@Published var text = ""
}
struct ContentView: View {
@StateObject private var viewModel = ContentViewViewModel()
var body: some View {
ZStack {
TextField("pla", text: $viewModel.text)
.padding()
}
// It still works without this modifier
//.onReceive(viewModel.$text) { text in
// print("run to onReceive \(text)")
//}
}
}
CodePudding user response:
I think it's because the view is automatically updated as your @Published
property in your ViewModel changes and the .onReceive
modifier updates the view yet again due to the 2 way binding created by viewModel.$text
resulting in the view being updated twice each time.
If you want to print the text as it changes you can use the .onChange
modifier instead.
class ContentViewViewModel: ObservableObject {
@Published var text = ""
}
struct ContentView: View {
@StateObject private var viewModel = ContentViewViewModel()
var body: some View {
ZStack {
TextField("pla", text: $viewModel.text)
.padding()
}.onChange(of: viewModel.text) { newValue in
print("run to onChange \(newValue)")
}
}
}