Depend on StackRouter/Actions from react-navigation
This commit is contained in:
parent
8d89cb2281
commit
a0a8f86ece
10
src/index.js
10
src/index.js
|
@ -13,16 +13,6 @@ module.exports = {
|
||||||
return require('./navigators/createStackNavigator').default;
|
return require('./navigators/createStackNavigator').default;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Router
|
|
||||||
*/
|
|
||||||
get StackRouter() {
|
|
||||||
return require('./routers/StackRouter').default;
|
|
||||||
},
|
|
||||||
get StackActions() {
|
|
||||||
return require('./routers/StackActions').default;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Views
|
* Views
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { createKeyboardAwareNavigator, createNavigator } from 'react-navigation';
|
import {
|
||||||
|
StackRouter,
|
||||||
|
createKeyboardAwareNavigator,
|
||||||
|
createNavigator,
|
||||||
|
} from 'react-navigation';
|
||||||
import StackView from '../views/StackView/StackView';
|
import StackView from '../views/StackView/StackView';
|
||||||
import StackRouter from '../routers/StackRouter';
|
|
||||||
|
|
||||||
function createStackNavigator(routeConfigMap, stackConfig = {}) {
|
function createStackNavigator(routeConfigMap, stackConfig = {}) {
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
let uniqueBaseId = `id-${Date.now()}`;
|
|
||||||
let uuidCount = 0;
|
|
||||||
|
|
||||||
export function _TESTING_ONLY_normalize_keys() {
|
|
||||||
uniqueBaseId = 'id';
|
|
||||||
uuidCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateKey() {
|
|
||||||
return `${uniqueBaseId}-${uuidCount++}`;
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
const POP = 'Navigation/POP';
|
|
||||||
const POP_TO_TOP = 'Navigation/POP_TO_TOP';
|
|
||||||
const PUSH = 'Navigation/PUSH';
|
|
||||||
const RESET = 'Navigation/RESET';
|
|
||||||
const REPLACE = 'Navigation/REPLACE';
|
|
||||||
const COMPLETE_TRANSITION = 'Navigation/COMPLETE_TRANSITION';
|
|
||||||
|
|
||||||
const pop = payload => ({
|
|
||||||
type: POP,
|
|
||||||
...payload,
|
|
||||||
});
|
|
||||||
|
|
||||||
const popToTop = payload => ({
|
|
||||||
type: POP_TO_TOP,
|
|
||||||
...payload,
|
|
||||||
});
|
|
||||||
|
|
||||||
const push = payload => ({
|
|
||||||
type: PUSH,
|
|
||||||
...payload,
|
|
||||||
});
|
|
||||||
|
|
||||||
const reset = payload => ({
|
|
||||||
type: RESET,
|
|
||||||
...payload,
|
|
||||||
});
|
|
||||||
|
|
||||||
const replace = payload => ({
|
|
||||||
type: REPLACE,
|
|
||||||
...payload,
|
|
||||||
});
|
|
||||||
|
|
||||||
const completeTransition = payload => ({
|
|
||||||
type: COMPLETE_TRANSITION,
|
|
||||||
...payload,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default {
|
|
||||||
POP,
|
|
||||||
POP_TO_TOP,
|
|
||||||
PUSH,
|
|
||||||
RESET,
|
|
||||||
REPLACE,
|
|
||||||
COMPLETE_TRANSITION,
|
|
||||||
|
|
||||||
pop,
|
|
||||||
popToTop,
|
|
||||||
push,
|
|
||||||
reset,
|
|
||||||
replace,
|
|
||||||
completeTransition,
|
|
||||||
};
|
|
|
@ -1,572 +0,0 @@
|
||||||
import {
|
|
||||||
NavigationActions,
|
|
||||||
createConfigGetter,
|
|
||||||
validateRouteConfigMap,
|
|
||||||
getScreenForRouteName,
|
|
||||||
StateUtils,
|
|
||||||
PathUtils,
|
|
||||||
} from 'react-navigation';
|
|
||||||
import StackActions from './StackActions';
|
|
||||||
import invariant from '../utils/invariant';
|
|
||||||
import { generateKey } from './KeyGenerator';
|
|
||||||
|
|
||||||
function behavesLikePushAction(action) {
|
|
||||||
return (
|
|
||||||
action.type === NavigationActions.NAVIGATE ||
|
|
||||||
action.type === StackActions.PUSH
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultActionCreators = (route, navStateKey) => ({});
|
|
||||||
|
|
||||||
function isResetToRootStack(action) {
|
|
||||||
return action.type === StackActions.RESET && action.key === null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (routeConfigs, stackConfig = {}) => {
|
|
||||||
// Fail fast on invalid route definitions
|
|
||||||
validateRouteConfigMap(routeConfigs);
|
|
||||||
|
|
||||||
const childRouters = {};
|
|
||||||
const routeNames = Object.keys(routeConfigs);
|
|
||||||
|
|
||||||
// Loop through routes and find child routers
|
|
||||||
routeNames.forEach(routeName => {
|
|
||||||
const screen = getScreenForRouteName(routeConfigs, routeName);
|
|
||||||
if (screen && screen.router) {
|
|
||||||
// If it has a router it's a navigator.
|
|
||||||
childRouters[routeName] = screen.router;
|
|
||||||
} else {
|
|
||||||
// If it doesn't have router it's an ordinary React component.
|
|
||||||
childRouters[routeName] = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const { initialRouteParams } = stackConfig;
|
|
||||||
const getCustomActionCreators =
|
|
||||||
stackConfig.getCustomActionCreators || defaultActionCreators;
|
|
||||||
|
|
||||||
const initialRouteName = stackConfig.initialRouteName || routeNames[0];
|
|
||||||
|
|
||||||
const initialChildRouter = childRouters[initialRouteName];
|
|
||||||
|
|
||||||
function getInitialState(action) {
|
|
||||||
let route = {};
|
|
||||||
const childRouter = childRouters[action.routeName];
|
|
||||||
|
|
||||||
// This is a push-like action, and childRouter will be a router or null if we are responsible for this routeName
|
|
||||||
if (behavesLikePushAction(action) && childRouter !== undefined) {
|
|
||||||
let childState = {};
|
|
||||||
// The router is null for normal leaf routes
|
|
||||||
if (childRouter !== null) {
|
|
||||||
const childAction =
|
|
||||||
action.action || NavigationActions.init({ params: action.params });
|
|
||||||
childState = childRouter.getStateForAction(childAction);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
key: 'StackRouterRoot',
|
|
||||||
isTransitioning: false,
|
|
||||||
index: 0,
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
params: action.params,
|
|
||||||
...childState,
|
|
||||||
key: action.key || generateKey(),
|
|
||||||
routeName: action.routeName,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialChildRouter) {
|
|
||||||
route = initialChildRouter.getStateForAction(
|
|
||||||
NavigationActions.navigate({
|
|
||||||
routeName: initialRouteName,
|
|
||||||
params: initialRouteParams,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const params = (route.params || action.params || initialRouteParams) && {
|
|
||||||
...(route.params || {}),
|
|
||||||
...(action.params || {}),
|
|
||||||
...(initialRouteParams || {}),
|
|
||||||
};
|
|
||||||
const { initialRouteKey } = stackConfig;
|
|
||||||
route = {
|
|
||||||
...route,
|
|
||||||
...(params ? { params } : {}),
|
|
||||||
routeName: initialRouteName,
|
|
||||||
key: action.key || (initialRouteKey || generateKey()),
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
key: 'StackRouterRoot',
|
|
||||||
isTransitioning: false,
|
|
||||||
index: 0,
|
|
||||||
routes: [route],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
getPathAndParamsForRoute,
|
|
||||||
getActionForPathAndParams,
|
|
||||||
} = PathUtils.createPathParser(childRouters, routeConfigs, stackConfig.paths);
|
|
||||||
|
|
||||||
return {
|
|
||||||
childRouters,
|
|
||||||
|
|
||||||
getComponentForState(state) {
|
|
||||||
const activeChildRoute = state.routes[state.index];
|
|
||||||
const { routeName } = activeChildRoute;
|
|
||||||
if (childRouters[routeName]) {
|
|
||||||
return childRouters[routeName].getComponentForState(activeChildRoute);
|
|
||||||
}
|
|
||||||
return getScreenForRouteName(routeConfigs, routeName);
|
|
||||||
},
|
|
||||||
|
|
||||||
getComponentForRouteName(routeName) {
|
|
||||||
return getScreenForRouteName(routeConfigs, routeName);
|
|
||||||
},
|
|
||||||
|
|
||||||
getActionCreators(route, navStateKey) {
|
|
||||||
return {
|
|
||||||
...getCustomActionCreators(route, navStateKey),
|
|
||||||
pop: (n, params) =>
|
|
||||||
StackActions.pop({
|
|
||||||
n,
|
|
||||||
...params,
|
|
||||||
}),
|
|
||||||
popToTop: params => StackActions.popToTop(params),
|
|
||||||
push: (routeName, params, action) =>
|
|
||||||
StackActions.push({
|
|
||||||
routeName,
|
|
||||||
params,
|
|
||||||
action,
|
|
||||||
}),
|
|
||||||
replace: (replaceWith, params, action, newKey) => {
|
|
||||||
if (typeof replaceWith === 'string') {
|
|
||||||
return StackActions.replace({
|
|
||||||
routeName: replaceWith,
|
|
||||||
params,
|
|
||||||
action,
|
|
||||||
key: route.key,
|
|
||||||
newKey,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
invariant(
|
|
||||||
typeof replaceWith === 'object',
|
|
||||||
'Must replaceWith an object or a string'
|
|
||||||
);
|
|
||||||
invariant(
|
|
||||||
params == null,
|
|
||||||
'Params must not be provided to .replace() when specifying an object'
|
|
||||||
);
|
|
||||||
invariant(
|
|
||||||
action == null,
|
|
||||||
'Child action must not be provided to .replace() when specifying an object'
|
|
||||||
);
|
|
||||||
invariant(
|
|
||||||
newKey == null,
|
|
||||||
'Child action must not be provided to .replace() when specifying an object'
|
|
||||||
);
|
|
||||||
return StackActions.replace(replaceWith);
|
|
||||||
},
|
|
||||||
reset: (actions, index) =>
|
|
||||||
StackActions.reset({
|
|
||||||
actions,
|
|
||||||
index: index == null ? actions.length - 1 : index,
|
|
||||||
key: navStateKey,
|
|
||||||
}),
|
|
||||||
dismiss: () =>
|
|
||||||
NavigationActions.back({
|
|
||||||
key: navStateKey,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getStateForAction(action, state) {
|
|
||||||
// Set up the initial state if needed
|
|
||||||
if (!state) {
|
|
||||||
return getInitialState(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeChildRoute = state.routes[state.index];
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isResetToRootStack(action) &&
|
|
||||||
action.type !== NavigationActions.NAVIGATE
|
|
||||||
) {
|
|
||||||
// Let the active child router handle the action
|
|
||||||
const activeChildRouter = childRouters[activeChildRoute.routeName];
|
|
||||||
if (activeChildRouter) {
|
|
||||||
const route = activeChildRouter.getStateForAction(
|
|
||||||
action,
|
|
||||||
activeChildRoute
|
|
||||||
);
|
|
||||||
if (route !== null && route !== activeChildRoute) {
|
|
||||||
return StateUtils.replaceAt(
|
|
||||||
state,
|
|
||||||
activeChildRoute.key,
|
|
||||||
route,
|
|
||||||
// the following tells replaceAt to NOT change the index to this route for the setParam action, because people don't expect param-setting actions to switch the active route
|
|
||||||
action.type === NavigationActions.SET_PARAMS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (action.type === NavigationActions.NAVIGATE) {
|
|
||||||
// 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()) {
|
|
||||||
let childRouter = childRouters[childRoute.routeName];
|
|
||||||
let childAction =
|
|
||||||
action.routeName === childRoute.routeName && action.action
|
|
||||||
? action.action
|
|
||||||
: action;
|
|
||||||
|
|
||||||
if (childRouter) {
|
|
||||||
const nextRouteState = childRouter.getStateForAction(
|
|
||||||
childAction,
|
|
||||||
childRoute
|
|
||||||
);
|
|
||||||
|
|
||||||
if (nextRouteState === null || nextRouteState !== childRoute) {
|
|
||||||
const newState = StateUtils.replaceAndPrune(
|
|
||||||
state,
|
|
||||||
nextRouteState ? nextRouteState.key : childRoute.key,
|
|
||||||
nextRouteState ? nextRouteState : childRoute
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
...newState,
|
|
||||||
isTransitioning:
|
|
||||||
state.index !== newState.index
|
|
||||||
? action.immediate !== true
|
|
||||||
: state.isTransitioning,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle explicit push navigation action. This must happen after the
|
|
||||||
// focused child router has had a chance to handle the action.
|
|
||||||
if (
|
|
||||||
behavesLikePushAction(action) &&
|
|
||||||
childRouters[action.routeName] !== undefined
|
|
||||||
) {
|
|
||||||
const childRouter = childRouters[action.routeName];
|
|
||||||
let route;
|
|
||||||
|
|
||||||
invariant(
|
|
||||||
action.type !== StackActions.PUSH || action.key == null,
|
|
||||||
'StackRouter does not support key on the push action'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Before pushing a new route we first try to find one in the existing route stack
|
|
||||||
// More information on this: https://github.com/react-navigation/rfcs/blob/master/text/0004-less-pushy-navigate.md
|
|
||||||
const lastRouteIndex = state.routes.findIndex(r => {
|
|
||||||
if (action.key) {
|
|
||||||
return r.key === action.key;
|
|
||||||
} else {
|
|
||||||
return r.routeName === action.routeName;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (action.type !== StackActions.PUSH && lastRouteIndex !== -1) {
|
|
||||||
// If index is unchanged and params are not being set, leave state identity intact
|
|
||||||
if (state.index === lastRouteIndex && !action.params) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the now unused routes at the tail of the routes array
|
|
||||||
const routes = state.routes.slice(0, lastRouteIndex + 1);
|
|
||||||
|
|
||||||
// Apply params if provided, otherwise leave route identity intact
|
|
||||||
if (action.params) {
|
|
||||||
const route = state.routes[lastRouteIndex];
|
|
||||||
routes[lastRouteIndex] = {
|
|
||||||
...route,
|
|
||||||
params: {
|
|
||||||
...route.params,
|
|
||||||
...action.params,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// Return state with new index. Change isTransitioning only if index has changed
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
isTransitioning:
|
|
||||||
state.index !== lastRouteIndex
|
|
||||||
? action.immediate !== true
|
|
||||||
: state.isTransitioning,
|
|
||||||
index: lastRouteIndex,
|
|
||||||
routes,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (childRouter) {
|
|
||||||
const childAction =
|
|
||||||
action.action || NavigationActions.init({ params: action.params });
|
|
||||||
route = {
|
|
||||||
params: action.params,
|
|
||||||
// merge the child state in this order to allow params override
|
|
||||||
...childRouter.getStateForAction(childAction),
|
|
||||||
routeName: action.routeName,
|
|
||||||
key: action.key || generateKey(),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
route = {
|
|
||||||
params: action.params,
|
|
||||||
routeName: action.routeName,
|
|
||||||
key: action.key || generateKey(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...StateUtils.push(state, route),
|
|
||||||
isTransitioning: action.immediate !== true,
|
|
||||||
};
|
|
||||||
} else if (
|
|
||||||
action.type === StackActions.PUSH &&
|
|
||||||
childRouters[action.routeName] === undefined
|
|
||||||
) {
|
|
||||||
// Return the state identity to bubble the action up
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle navigation to other child routers that are not yet pushed
|
|
||||||
if (behavesLikePushAction(action)) {
|
|
||||||
const childRouterNames = Object.keys(childRouters);
|
|
||||||
for (let i = 0; i < childRouterNames.length; i++) {
|
|
||||||
const childRouterName = childRouterNames[i];
|
|
||||||
const childRouter = childRouters[childRouterName];
|
|
||||||
if (childRouter) {
|
|
||||||
// For each child router, start with a blank state
|
|
||||||
const initChildRoute = childRouter.getStateForAction(
|
|
||||||
NavigationActions.init()
|
|
||||||
);
|
|
||||||
// Then check to see if the router handles our navigate action
|
|
||||||
const navigatedChildRoute = childRouter.getStateForAction(
|
|
||||||
action,
|
|
||||||
initChildRoute
|
|
||||||
);
|
|
||||||
let routeToPush = null;
|
|
||||||
if (navigatedChildRoute === null) {
|
|
||||||
// Push the route if the router has 'handled' the action and returned null
|
|
||||||
routeToPush = initChildRoute;
|
|
||||||
} else if (navigatedChildRoute !== initChildRoute) {
|
|
||||||
// Push the route if the state has changed in response to this navigation
|
|
||||||
routeToPush = navigatedChildRoute;
|
|
||||||
}
|
|
||||||
if (routeToPush) {
|
|
||||||
const route = {
|
|
||||||
...routeToPush,
|
|
||||||
routeName: childRouterName,
|
|
||||||
key: action.key || generateKey(),
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
...StateUtils.push(state, route),
|
|
||||||
isTransitioning: action.immediate !== true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle pop-to-top behavior. Make sure this happens after children have had a chance to handle the action, so that the inner stack pops to top first.
|
|
||||||
if (action.type === StackActions.POP_TO_TOP) {
|
|
||||||
// Refuse to handle pop to top if a key is given that doesn't correspond
|
|
||||||
// to this router
|
|
||||||
if (action.key && state.key !== action.key) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're already at the top, then we return the state with a new
|
|
||||||
// identity so that the action is handled by this router.
|
|
||||||
if (state.index > 0) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
isTransitioning: action.immediate !== true,
|
|
||||||
index: 0,
|
|
||||||
routes: [state.routes[0]],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle replace action
|
|
||||||
if (action.type === StackActions.REPLACE) {
|
|
||||||
let routeIndex;
|
|
||||||
|
|
||||||
// If the key param is undefined, set the index to the last route in the stack
|
|
||||||
if (action.key === undefined && state.routes.length) {
|
|
||||||
routeIndex = state.routes.length - 1;
|
|
||||||
} else {
|
|
||||||
routeIndex = state.routes.findIndex(r => r.key === action.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only replace if the key matches one of our routes
|
|
||||||
if (routeIndex !== -1) {
|
|
||||||
const childRouter = childRouters[action.routeName];
|
|
||||||
let childState = {};
|
|
||||||
if (childRouter) {
|
|
||||||
const childAction =
|
|
||||||
action.action ||
|
|
||||||
NavigationActions.init({ params: action.params });
|
|
||||||
childState = childRouter.getStateForAction(childAction);
|
|
||||||
}
|
|
||||||
const routes = [...state.routes];
|
|
||||||
routes[routeIndex] = {
|
|
||||||
params: action.params,
|
|
||||||
// merge the child state in this order to allow params override
|
|
||||||
...childState,
|
|
||||||
routeName: action.routeName,
|
|
||||||
key: action.newKey || generateKey(),
|
|
||||||
};
|
|
||||||
return { ...state, routes };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update transitioning state
|
|
||||||
if (
|
|
||||||
action.type === StackActions.COMPLETE_TRANSITION &&
|
|
||||||
(action.key == null || action.key === state.key) &&
|
|
||||||
state.isTransitioning
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
isTransitioning: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === NavigationActions.SET_PARAMS) {
|
|
||||||
const key = action.key;
|
|
||||||
const lastRoute = state.routes.find(route => route.key === key);
|
|
||||||
if (lastRoute) {
|
|
||||||
const params = {
|
|
||||||
...lastRoute.params,
|
|
||||||
...action.params,
|
|
||||||
};
|
|
||||||
const routes = [...state.routes];
|
|
||||||
routes[state.routes.indexOf(lastRoute)] = {
|
|
||||||
...lastRoute,
|
|
||||||
params,
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
routes,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === StackActions.RESET) {
|
|
||||||
// Only handle reset actions that are unspecified or match this state key
|
|
||||||
if (action.key != null && action.key != state.key) {
|
|
||||||
// Deliberately use != instead of !== so we can match null with
|
|
||||||
// undefined on either the state or the action
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
const newStackActions = action.actions;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
routes: newStackActions.map(newStackAction => {
|
|
||||||
const router = childRouters[newStackAction.routeName];
|
|
||||||
|
|
||||||
let childState = {};
|
|
||||||
|
|
||||||
if (router) {
|
|
||||||
const childAction =
|
|
||||||
newStackAction.action ||
|
|
||||||
NavigationActions.init({ params: newStackAction.params });
|
|
||||||
|
|
||||||
childState = router.getStateForAction(childAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
params: newStackAction.params,
|
|
||||||
...childState,
|
|
||||||
routeName: newStackAction.routeName,
|
|
||||||
key: newStackAction.key || generateKey(),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
index: action.index,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
action.type === NavigationActions.BACK ||
|
|
||||||
action.type === StackActions.POP
|
|
||||||
) {
|
|
||||||
const { key, n, immediate } = action;
|
|
||||||
let backRouteIndex = state.index;
|
|
||||||
if (action.type === StackActions.POP && n != null) {
|
|
||||||
// determine the index to go back *from*. In this case, n=1 means to go
|
|
||||||
// back from state.index, as if it were a normal "BACK" action
|
|
||||||
backRouteIndex = Math.max(1, state.index - n + 1);
|
|
||||||
} else if (key) {
|
|
||||||
const backRoute = state.routes.find(route => route.key === key);
|
|
||||||
backRouteIndex = state.routes.indexOf(backRoute);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (backRouteIndex > 0) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
routes: state.routes.slice(0, backRouteIndex),
|
|
||||||
index: backRouteIndex - 1,
|
|
||||||
isTransitioning: immediate !== true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// By this point in the router's state handling logic, we have handled the behavior of the active route, and handled any stack actions.
|
|
||||||
// If we haven't returned by now, we should allow non-active child routers to handle this action, and switch to that index if the child state (route) does change..
|
|
||||||
|
|
||||||
const keyIndex = action.key ? StateUtils.indexOf(state, action.key) : -1;
|
|
||||||
|
|
||||||
// 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 (childRoute.key === activeChildRoute.key) {
|
|
||||||
// skip over the active child because we let it attempt to handle the action earlier
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
// the following tells replaceAt to NOT change the index to this route for the setParam action, because people don't expect param-setting actions to switch the active route
|
|
||||||
action.type === NavigationActions.SET_PARAMS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
},
|
|
||||||
|
|
||||||
getPathAndParamsForState(state) {
|
|
||||||
const route = state.routes[state.index];
|
|
||||||
return getPathAndParamsForRoute(route);
|
|
||||||
},
|
|
||||||
|
|
||||||
getActionForPathAndParams(path, params) {
|
|
||||||
return getActionForPathAndParams(path, params);
|
|
||||||
},
|
|
||||||
|
|
||||||
getScreenOptions: createConfigGetter(
|
|
||||||
routeConfigs,
|
|
||||||
stackConfig.navigationOptions
|
|
||||||
),
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { NativeModules } from 'react-native';
|
import { NativeModules } from 'react-native';
|
||||||
|
|
||||||
|
import { StackActions } from 'react-navigation';
|
||||||
import StackViewLayout from './StackViewLayout';
|
import StackViewLayout from './StackViewLayout';
|
||||||
import Transitioner from '../Transitioner';
|
import Transitioner from '../Transitioner';
|
||||||
import StackActions from '../../routers/StackActions';
|
|
||||||
import TransitionConfigs from './StackViewTransitionConfigs';
|
import TransitionConfigs from './StackViewTransitionConfigs';
|
||||||
|
|
||||||
const NativeAnimatedModule =
|
const NativeAnimatedModule =
|
||||||
|
|
|
@ -11,11 +11,16 @@ import {
|
||||||
Easing,
|
Easing,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { SceneView, NavigationActions, withOrientation, NavigationProvider } from 'react-navigation';
|
import {
|
||||||
|
SceneView,
|
||||||
|
StackActions,
|
||||||
|
NavigationActions,
|
||||||
|
withOrientation,
|
||||||
|
NavigationProvider,
|
||||||
|
} from 'react-navigation';
|
||||||
|
|
||||||
import Card from './StackViewCard';
|
import Card from './StackViewCard';
|
||||||
import Header from '../Header/Header';
|
import Header from '../Header/Header';
|
||||||
import StackActions from '../../routers/StackActions';
|
|
||||||
|
|
||||||
import TransitionConfigs from './StackViewTransitionConfigs';
|
import TransitionConfigs from './StackViewTransitionConfigs';
|
||||||
import { supportsImprovedSpringAnimation } from '../../utils/ReactNativeFeatures';
|
import { supportsImprovedSpringAnimation } from '../../utils/ReactNativeFeatures';
|
||||||
|
|
Loading…
Reference in New Issue