TextField binding not updating on iOS17 #2716
-
DescriptionIn the case where BindingState is updated directly in the action that updated it the TextField value is not updated. Minimal reproducible example: import SwiftUI
import ComposableArchitecture
@main
struct TestBindingApp: App {
var body: some Scene {
WindowGroup {
ContentView().task {
runTest()
}
}
}
}
@Reducer
struct SomeReducer {
struct State: Equatable {
@BindingState var text = ""
}
enum Action: BindableAction {
case binding(BindingAction<State>)
}
var body: some ReducerOf<Self> {
BindingReducer()
Reduce { state, action in
switch action {
case .binding(\.$text):
if state.text == "123" {
state.text = ""
}
case .binding:
break
}
return .none
}
}
}
struct ViewState: Equatable {
@BindingViewState var text: String
init(state: BindingViewStore<SomeReducer.State>) {
self._text = state.$text
}
}
struct ContentView: View {
let store = Store(initialState: .init()) {
SomeReducer()._printChanges()
}
var body: some View {
WithViewStore(store, observe: ViewState.init) { viewStore in
VStack {
Text(viewStore.text)
TextField("Title", text: viewStore.$text).textFieldStyle(.plain)
}
}
}
} Checklist
Expected behaviorIn the above example I would expect both Text and TextField values to reset to empty string if I type in "123". Actual behaviorThe value of the Text updates, but the value of the TextField stays "123". Screen.Recording.2024-01-19.at.10.43.17.movSteps to reproduceNo response The Composable Architecture version information1.6.0 Destination operating systemiOS 17 Xcode version information15.2 Swift Compiler version informationswift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
Target: arm64-apple-macosx13.0 |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
@marioradonic How did you rule out this behavior in vanilla SwiftUI? If I use a vanilla observable object instead of a store I can reproduce the exact same behavior: class Model: ObservableObject {
@Published var text = "" {
didSet {
if text == "123" {
text = ""
}
}
}
}
struct ContentView: View {
@ObservedObject var model = Model()
var body: some View {
VStack {
Text(model.text)
TextField("Title", text: $model.text).textFieldStyle(.plain)
}
}
} Because this appears to be a vanilla SwiftUI behavior and not a bug in TCA, I'm going to convert to a discussion, where workarounds may be discussed. |
Beta Was this translation helpful? Give feedback.
-
I have stumbled upon this issue today and for me the easiest fix was to add a new action which handles the validation of the input. In the binding action for the input I then used the This is clearly not ideal as the UI shows the entered character for a brief moment, but for our use case it was sufficient and easier then doing anything with |
Beta Was this translation helpful? Give feedback.
@marioradonic How did you rule out this behavior in vanilla SwiftUI? If I use a vanilla observable object instead of a store I can reproduce the exact same behavior:
Because this appears to be a vanilla SwiftUI behavior and not a bug in TCA, I'm going to convert to a discussion, where workarounds may be discussed.