2

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)")
        }
    }
}

enter image description here

1
  • This question is similar to: .onReceive firing twice | SwiftUI. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Jan 18 at 20:37

2 Answers 2

0

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)")
        //}
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

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)")
        }
    }
}

onChanged in SwiftUI

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.