Simple way to get input from a child view #1526
-
New to TCA and Swift and have a couple of issues I have been unable to sort out as I convert my first big feature to TCA using the Case Studies as examples. Everything as gone well and I have one hurdle to get some input data from a sheet that has two text fields and an Add button which verifies the input and closes the sheet. To allow testing the rest of the code I just added two stubbed values so I could complete and test the feature. Here is the sheet code:
The original code I had used Bindings to pass the state but
that seems weird now and even when I tried using TCA bindings I failed to get it compiled or make it work. I thought I could hold on to the ViewStore for AddVehicleView() but I could not figure a way access the state after the view closed as a WithViewStore() wrapper is needed to get into the store state or I am not in a View. Any ideas out there to solve this? I have been staring at the SharedState example code as a model for doing this but it has so much extra complexity I an hoping for a simpler solution and haven't found any similar threads using the new ReducerProtocol. In the meantime I am going to write my first tests, which is why I chose TCA in the first place.🤓 |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 4 replies
-
Shared state is really tough (see my posing of the problem here: #1445 and attempted solutions here #1445 (comment)). You're going to have to do some codegen for the optimal, no-repetition solution (any ancestor has to have as a generated property every descendant touching shared state). I haven't heard from the creators that there's nothing in the works, so for now I'm hoping someone comes up with a nicer solution and I'm instead just repeating state and using single-level generated properties to achieve the injection. More concretely, a compromise between quality and brevity looks like the following:
(and then for further nesting repeated inside You're going to have duplication of the |
Beta Was this translation helpful? Give feedback.
-
I don't think you need shared state for this as the parent has access to the child state so when the dismiss action fire, before setting the child to nil you can use the child state to create you object. |
Beta Was this translation helpful? Give feedback.
-
I agree with @Alex293, and don't think this requires "shared state" in the sense that the parent wants to share state with the child. The reverse, that of the child sharing state with the parent, is implicit due to the fact that parent features hold onto all of the state of the child. The way you can handle your situation is to have an struct AddVehicleFeature: ReducerProtocol {
struct State { … }
enum Action {
case addButtonTapped
…
}
…
} And the Then in the parent, you can listen for that action, and perform the validation and adding logic: struct VehicleFeature: ReducerProtocol {
struct State {
var addVehicle: AddVehicleFeature.State
var isAddVehicleSheetPresented = false
…
}
enum Action {
case addVehicle(AddVehicleFeature.Action)
…
}
var body: some ReducerProtocol<State, Action> {
Scope(state: \.addVehicle, action: /Action.addVehicle) {
AddVehicleFeature()
}
Reduce { state, action in
switch action {
case .addVehicle(.addButtonTapped):
// Validate state.addVehicle and perform logic
}
}
}
} That's the rough idea at least. If you can share a complete code sample we may be able to provide more help. Once you get the basics down there are a few extra directions you could go to strengthen this feature. First, instead of holding onto Second, right now the validation logic lives in the parent feature, but maybe you want to it to be in the child, and then once the child validates it communicates back to the parent that it is OK to add the vehicle. This can be done with an ad-hoc pattern of "delegate actions", where the child sends an action to itself that the parent listens to and interprets. We have a bunch of examples of this in our isowords project, and @krzysztofzablocki wrote a blog post about this pattern |
Beta Was this translation helpful? Give feedback.
-
Ah my bad, I thought you needed the bidirectionality because of the binding. Delegate should work fine here, Oops! |
Beta Was this translation helpful? Give feedback.
-
Tried some of the ideas, was able to find a way forward but not using parent/child state. While I have the child reducer cases in the parent reducer they are never called so obviously I am missing something. I reduced the code to a minimum so perhaps someone can point out a flaw in the code and get me on the right track. If not, I'll be downloading IsoWords and seeing how the delegate method is used. Parent: VehicleFeature.swift
Child: NewVehicle.swift
|
Beta Was this translation helpful? Give feedback.
I agree with @Alex293, and don't think this requires "shared state" in the sense that the parent wants to share state with the child. The reverse, that of the child sharing state with the parent, is implicit due to the fact that parent features hold onto all of the state of the child.
The way you can handle your situation is to have an
addButtonTapped
action in your child feature:And the
AddVehicleFeature
doesn't need to handle the logic for that action. It just needs to the view to send it so that the parent can see it.Then in the parent, you can listen for that ac…