SwiftUI TextField re-renders the view after each character typed. How do I make it to re-render the view only after hitting the Return key? See the code below.

struct ContentView: View {

@State var someText = "Change me!"

@State var someNumber = 123.0

var body: some View {

Form {

// The entire View is re-rendered after each character is typed

TextField("Text", text: $someText,

onEditingChanged: { edit in

print("onEditingChanged executed!")

},

onCommit: {

print("onCommit executed!")

}

)

// When you enter a Double value, the View is not re-rendered until you hit Return

TextField("Number", value: $someNumber, formatter: NumberFormatter())

Spacer()

Text("text: \(self.someText), number: \(self.someNumber)")

}

}

}

Replies

What you're seeing is the correct behavior. When the @State value changes it re-runs the body to update the View. As far as I can tell, this is required by the TextField since beta 4 or 5. Previously, the text would stay as it was after typing, but now it only shows the new characters after its containing view is updated.


What you see in SwiftUI is not the actual view, but a defintion object used to build and update the real view. Because of this, the view itself is not actually getting rebuilt. It's simply getting updated with the new text value.

All I want is a TextField to search an API. It makes an API call after each character entered returning invalid results from API unnecessarily. TextField must have a modifier to provide an option for either changing the @State var char by char or only onCommit. I can present the TextField in another view so re-rendering doesn't do anything and put the search string into a global var, but that is an ugly solution.

What you likely need is to use the

.debounce()
operator on whatever binding you're using to feed into your API. There's a discussion and example of exactly what you describe in the Combine in Practice WWDC session, beginning around 24:40 into the video.

No SwiftUI view or control has a .debounce() modifier.

Thanks for this, helped me with some experimenting that I was doing earlier. The '.debounce()' section starts at 29:20 in the linked WWDC session.