jecht83
(Julio Montoya)
1
While working with NavigationStackStore found really easy to read actions from child features presented by Path like:
case let .path(action):
switch action {
case .element(id: _, action: .screenB(.screenAButtonTapped)):
state.path.append(.screenA())
return .none
}
}
but couldn't find a way to send actions from path to a child feature,
is it possible?
like the following:
return .send(.path(.child1(.initialize)))
otondin
(Gabriel Tondin)
2
Hey @jecht83 ! I think it isn't a good practice to call actions from parent to child. Usually, I tend - to get a more coherent system - to re-create child states. Please, look at this example, which handles an identified array of states, to check if it fits your case.
mbrandonw
(Brandon Williams)
3
It is not recommend to share logic between domains by sending actions like this. We have this details in the docs.
The article above describes some alternatives, such as a mutating func on the child state, and the way you use that technique with StackState is like the following:
case let .element(id: id, action: …):
state.path[id: id]?.someMutatingFunc()
1 Like
jecht83
(Julio Montoya)
4
That's exactly what I was looking for
A way to demonstrate that the parent feature calling actions from it's child
is not a good approach backed up with documentation
And an option to work with mutating funcs in StackState
Thanks for your time
jecht83
(Julio Montoya)
5
By following this approach added a mutating func into the Child and got the error
// Path.State does not contain mutating func
case let .element(id: id, action: …):
state.path[id: id]?.someMutatingFunc()
// Cast from 'ContentFeature.Path.State?' to unrelated type 'SettingsFeature.State' always fails
case let .element(id: id, action: …):
if let settingsState = state.path[id: id] as? SettingsFeature.State {
settingsState.someMutatingFunc()
}
return .none
Also documentation recommends another approach, is this working with navigation stack?
case .buttonTapped:
return Child().reduce(into: &state.child, action: .refresh)
.map(Action.child)
Tried something like:
return SettingsFeature()
.reduce(into: &state.path[id: id]!, action: .updateSettings)
.map(Path.Action.settings)
any suggestion?
mbrandonw
(Brandon Williams)
6
I'm guessing that Path.State is an enum of all the features that can be pushed on the stack, and so that is why there is no mutating function. You are probably wanting to call a mutating function on a particular case of the enum.
You can do this using the [id:case:] subscript on StackState:
state.path[id: id, case: \.settings]?.someMethod()
And you can use that subscript with reduce(into:action:) too.
1 Like
jecht83
(Julio Montoya)
7
In my case it worked with:
state.path[id: id, case: /Path.State.settings]?.someMethod()
Thanks for your help
mbrandonw
(Brandon Williams)
8
If you upgrade to using the newest version of TCA and the @Reducer macro you can shorten that to just case: \.settings.
jecht83
(Julio Montoya)
9
I've been limited by my OS version but I'll try to update to the latest, thank you
jecht83
(Julio Montoya)
10
OK one last thing, I can not make the reduce subscript to work with navigation stack store
I've tried the following with no success:
return SettingsFeature()
.reduce(into: &state.path[id: id, case: \.settings]!, action: .refresh)
.map(Path.Action.settings) // Type of expression is ambiguous without a type annotation
@mbrandonw, how can I make it work with StackStore?
mbrandonw
(Brandon Williams)
11
The .map on the effect needs to bundle a settings action back into the path. So it's a bit more complex:
.map { .path(.element(id: id, action: $0)) }
jecht83
(Julio Montoya)
12
I really hate to bother you, tried the following code with no success
return SettingsFeature()
.reduce(
into: &state.path[id: id, case: /Path.State.settings]!,
action: .updateTitle
)
.map { .path(.element(id: id, action: $0)) }
// Error: Cannot convert value of type 'SettingsFeature.Action'
// to expected argument type 'ContentFeature.Path.Action'
mbrandonw
(Brandon Williams)
13
Ah sorry, it should be:
.map { .path(.element(id: id, action: .settings($0))) }
Or whatever the name of the case for settings is inside the Path.Action enum.
1 Like
jecht83
(Julio Montoya)
14
That did the trick, thank you so much for your help
Hi @mbrandonw do you know if i can access a different element id inside the stack while the current id is different? maybe hardcode the id number and access the state, for instance:
let customID: 3 as StackElementID
var customState = state.path[id: customID, case: \Settings]
if isn't possible, which looks like it isn't since it does crashes.
how could i update a different type of state while receiving an action from my root reducer from a different state, for instance:
case let .path(.element(id: id, action: .photoFiltering(.nextButtonTapped))):
// here access different path and change property inside it