During my testing, I've found that there's a few issues related to using nested navigators:
1. State being dispatched from navigation change should be 'unpacked' accoding to current state
In useWebviewNavigate
we first use getStateFromPath(..)
to translate a path to a desired state. For replace
actions, we "unpack" the state, meaning that for nested screens, we dig out the bottom-most leaf and dispatch that.
The problem here is that we'd like to unpack state, but only up to a point where the new state differ from the current state. We want to do that for both advance
and replace
actions. We should recursively remove the parent(s) from the new state that is also shared with the current state, so that the new state we dispatch - and which is bubbled up - is handled by the bottom-most shared navigator.
Example:
# Current state:
Screen A
Screen B
Screen C
# Proposed new state from getStateFromPath:
Screen A
Screen B
Screen Y
In this case, we’d like to getActionFromState(..)
with ‘Screen A’ and ‘Screen B’ removed, as they are shared between the two, eg Screen Y
. As we bubble up from the bottom-most navigator, the action will be handled by Screen B
Example 2:
# Current state:
Screen A
Screen B
Screen C
# Proposed new state from getStateFromPath:
Screen A
Screen Z
Screen Y
In this case, since only Screen A
matches both, we'd like to dispatch:
2. key
added to the dispatched action is added to the root screen and not to the bottom-most screen when dispatchin
We are using key
to ensure that pushing the same screen, but with an different params/URL set would be considered a new screen (ie. useful for Fallback
screens). We are adding the key
to the root object.
I'm thinking here that for nested navigators, with state unpacked as above, we'd like to add the key
to the bottom-most screen and not the root screen. This ensures that the nested navigator object is not re-added (which sometimes triggers animations!) but merely the bottom-most screen would be considered changed.
On a side note, it seems that key
is removed in React Navigation 7.0. Maybe it's better to find a different pattern for doing this?
3. Logic to determine if setParams(..)
is wrong with nested navigators.
I have a feeling that this would be solved by the first issue mentioned above. Today we are comparing the name of the root screen being pushed (action.payload.name == routeName
) to determine if we can use setParams(..)
.
This doesn't work well with nested navigators, as the root screen (action.payload.name
) today might refer to a parent navigator instead of the actual current screen (routeName
). Instead, we should compare the names of all the leaves between the two states to ensure that they're identical.