BruceRick
(Bruce Rick)
1
When viewing the documentation comment it states:
Derives a binding from the store that prevents direct writes to state and instead sends
actions to the store.
The method is useful for dealing with SwiftUI components that work with two-way Bindings
since the Store does not allow directly writing its state; it only allows reading state and
sending actions.
For example, a text field binding can be created like this:
struct State { var name = "" }
enum Action { case nameChanged(String) }
TextField(
"Enter name",
text: viewStore.binding(
send: { Action.nameChanged($0) }
)
)
- Parameters:
- localStateToViewAction: A function that transforms the binding's value
into an action that can be sent to the store.
- Returns: A binding.
However doing something like the following produces an error.
struct TestView: View {
struct TestState { var name = "" }
enum TestAction { case nameChanged(String) }
let store: Store<TestState, TestAction>
var body: some View {
WithViewStore(store) { viewStore in
TextField(
"Enter name",
text: viewStore.binding(
send: { TestAction.nameChanged($0) }
)
)
}
}
}
I'm just wondering if I'm misunderstanding the usage of binding(send: )? What is the expected usage of this method?
BruceRick
(Bruce Rick)
2
TextField(
"Enter name",
text: viewStore.binding(
send: { TestAction.nameChanged($0) }
)
)
I'm not quite sure how the above would work? binding(send: ) is returning Binding<State> when text is expecting a Binding<String> ? binding(get: send:) returns Binding<LocalState> which would map to Binding<String>
Is it possible the documentation is incorrect or out of date? I'm still curious if this (a binding which only sends an action?) is possible if so? Making a binding to a textField thats only one way wouldn't make a whole lot of sense in this situation obviously but a use case like the following may make a one way binding useful:
struct ImageSelectorView: View {
@Binding var image: Image
... Selects an image from the camera role
}
struct ImagesView: View {
struct State { var images: [Image] = [] }
enum Action { case add(Image) }
let store: Store<State, Action>
var body: some View {
WithViewStore(store) { viewStore in
List {
... viewStore.images
}
Button {
show(ImageSelectorView(image: viewStore.binding(send: .addImage($0))
} label: {
Text("ADD")
}
}
}
}
In all honesty using a closure instead of an Image Binding would obviously work, or even binding(get: Image(""), send: { .add($0) }) so this question is more just to satisfy my own curiosity. And my initial interpretation of the documentation comment was that I should indeed be able to do just binding(send:).
mbrandonw
(Brandon Williams)
3
This is just a typo in the docs. The binding overload that does not take a state transformation is useful for when your view store already holds the value you want to bind.
I've updated the docs here:
Thanks for bring this to our attention!
1 Like