Delegate to child routers for more than just the top screen in the stack (#4587)

* Delegate to child routers for more than just the top screen in the stack. Fixes #4185

* Add CHANGELOG entry
This commit is contained in:
Brent Vatne 2018-06-27 17:37:30 -07:00 committed by GitHub
parent bc01a4cd57
commit c7fff52408
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 17 deletions

View File

@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
- Delegate to child routers for more than just the top screen in the stack.
- Throw error in development mode when header navigation option is set to a string - a common mistake that would otherwise result in a cryptic error message.
- Update react-navigation-drawer to 0.4.3 to fix `initialRouteParams` option
- Throw error in development mode when title is not a string.

View File

@ -133,10 +133,15 @@ const StateUtils = {
* Replace a route by a key.
* Note that this moves the index to the position to where the new route in the
* stack is at. Does not prune the routes.
* If preserveIndex is true then replacing the route does not cause the index
* to change to the index of that route.
*/
replaceAt(state, key, route) {
replaceAt(state, key, route, preserveIndex = false) {
const index = StateUtils.indexOf(state, key);
return StateUtils.replaceAtIndex(state, index, route);
const nextIndex = preserveIndex ? state.index : index;
let nextState = StateUtils.replaceAtIndex(state, index, route);
nextState.index = nextIndex;
return nextState;
},
/**

View File

@ -225,8 +225,6 @@ export default (routeConfigs, stackConfig = {}) => {
return getInitialState(action);
}
// Check if the focused child scene wants to handle the action, as long as
// it is not a reset to the root stack
if (
!isResetToRootStack(action) &&
action.type !== NavigationActions.NAVIGATE
@ -234,20 +232,30 @@ export default (routeConfigs, stackConfig = {}) => {
const keyIndex = action.key
? StateUtils.indexOf(state, action.key)
: -1;
const childIndex = keyIndex >= 0 ? keyIndex : state.index;
const childRoute = state.routes[childIndex];
invariant(
childRoute,
`StateUtils erroneously thought index ${childIndex} exists`
);
const childRouter = childRouters[childRoute.routeName];
if (childRouter) {
const route = childRouter.getStateForAction(action, childRoute);
if (route === null) {
return state;
// Traverse routes from the top of the stack to the bottom, so the
// active route has the first opportunity, then the one before it, etc.
for (let childRoute of state.routes.slice().reverse()) {
// If a key is provided and in routes state then let's use that
// knowledge to skip extra getStateForAction calls on other child
// routers
if (keyIndex >= 0 && childRoute.key !== action.key) {
continue;
}
if (route && route !== childRoute) {
return StateUtils.replaceAt(state, childRoute.key, route);
let childRouter = childRouters[childRoute.routeName];
if (childRouter) {
const route = childRouter.getStateForAction(action, childRoute);
if (route === null) {
return state;
} else if (route && route !== childRoute) {
return StateUtils.replaceAt(
state,
childRoute.key,
route,
action.type === NavigationActions.SET_PARAMS
);
}
}
}
} else if (action.type === NavigationActions.NAVIGATE) {