-
I have a Here's a sample project that shows the issue if you want to test it, but this is the Child Reducer
@Reducer
struct Child {
@ObservableState
struct State {
var value = ""
}
enum Action: BindableAction {
case binding(BindingAction<State>)
case cancelButtonTapped
}
@Dependency(\.dismiss) var dismiss
var body: some ReducerOf<Self> {
BindingReducer()
Reduce { state, action in
switch action {
case .cancelButtonTapped:
return .run { [dismiss] send in
await dismiss()
}
case .binding:
return .none
}
}
}
}
struct ChildView: View {
@Bindable var store: StoreOf<Child>
var body: some View {
TextField(
"Child",
text: Binding(
get: { store.value },
set: { store.send(.binding(.set(\.value, $0))) }
)
)
.textFieldStyle(.roundedBorder)
.frame(maxWidth: 200)
.toolbar {
Button("Cancel") {
store.send(.cancelButtonTapped)
}
}
}
} When you bind the TextField("Child", text: $store.value) But when you do it like this you get a runtime warning: TextField(
"Child",
text: Binding(
get: { store.value },
set: { store.send(.binding(.set(\.value, $0))) }
)
) Runtime warning
Sending a specific action instead of a binding action has the same result: TextField(
"Child",
text: Binding(
get: { store.value },
set: { store.send(.valueChanged($0)) }
)
) If I Console output
Not sure what I was looking for, but I also tried a vanilla SwiftUI version to see if I could gain any insight. This works as expected, but gave me no guidance on the TCA version: Vanilla version
struct VanillaParent: View {
@State private var showSheet = false
var body: some View {
Button("Show Sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
NavigationStack {
VanillaChild()
}
}
}
}
struct VanillaChild: View {
@State private var value = ""
@Environment(\.dismiss) var dismiss
var body: some View {
TextField("Child", text: $value)
.textFieldStyle(.roundedBorder)
.frame(maxWidth: 200)
.toolbar {
Button("Cancel") { dismiss() }
}
}
} There seems to be some magic happening when you use a Can't seem to make any headway on this, so I'd appreciate any help I can get. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Hi @seanmrich, is there a reason you are constructing a binding from scratch instead of using the tools of the library? Like this: text: $store.value If you do that the runtime warning is suppressed. The reason the runtime warning is happening is because as the child view is dismissed, SwiftUI writes to the text field binding (for some reason). That causes an action to be sent, and by that point the state has been And so we have special logic in the library for suppressing the warning under certain circumstances. If you use the binding helpers you will get access to that functionality. Also, in general, it is not a good idea to construct bindings with |
Beta Was this translation helpful? Give feedback.
Hi @seanmrich, is there a reason you are constructing a binding from scratch instead of using the tools of the library? Like this:
text: $store.value
If you do that the runtime warning is suppressed.
The reason the runtime warning is happening is because as the child view is dismissed, SwiftUI writes to the text field binding (for some reason). That causes an action to be sent, and by that point the state has been
nil
'd out, and hence the warning. Really it's a SwiftUI bug, but we've long lost hope of it ever being fixed.And so we have special logic in the library for suppressing the warning under certain circumstances. If you use the binding helpers you will get access to that functiona…