-
Notifications
You must be signed in to change notification settings - Fork 3
Closed
Description
Hi, I've been playing around with Recombine, and really enjoying it, but I've noticed a hole: creating bindings.
Take this example:
struct ContentView: View {
@EnvironmentObject var store: Store
var body: some View {
TextField("Username", text: ??)
}
}What should be put as a binding? One might first think this:
TextField("Username", text: $store.state.username) // ERROR - Cannot assign to property: 'state' setter is inaccessibleBut, no, we can't - and thankfully so, since here we'd be bypassing the reducer.
To solve this problem, I offer that this function be added in an extension to BaseStore:
extension BaseStore {
/// Create a SwiftUI Binding from a state property and a refined action
/// - Parameters:
/// - keyPath: A keypath to the state property.
/// - action: The refined action which will be called when the value is changed.
/// - Returns: A Binding, who's getter is the property and who's setter is the refined action taking the value of the property.
func binding<Value>(for keyPath: KeyPath<SubState, Value>, action: @escaping (Value) -> SubRefinedAction) -> Binding<Value> {
Binding<Value>(
get: { self.state[keyPath: keyPath]},
set: { self.dispatch(refined: action($0)) }
)
}
Now, we can do this:
TextField("Username", text: store.binding(for: \.username, action: { .setUsername($0) }))or this:
TextField("Username", text: store.binding(for: \.username, action: Redux.Action.Refined.setUsername)And for a cleaner body declaration, factor out the binding:
struct ContentView: View {
@EnvironmentObject var store: Store
private var usernameBinding: Binding<String> {
store.binding(for: \.username, action: { .setUsername($0) })
}
var body: some View {
TextField("Username", text: usernameBinding)
}
}I've tested this out, and it works like a charm. We could also do the same for raw actions, but that's for you to choose.
I haven't found a way to implement this for lensed stores. Optimally, we'd want a function on StoreProtocol, so that it works for both.
Let me know what you think!
Metadata
Metadata
Assignees
Labels
No labels