mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-25 13:05:26 +08:00
Implement "less pushy navigate" RFC
This commit is contained in:
@@ -196,42 +196,46 @@ export default (routeConfigs, stackConfig = {}) => {
|
||||
'StackRouter does not support key on the push action'
|
||||
);
|
||||
|
||||
// With the navigate action, the key may be provided for pushing, or to navigate back to the key
|
||||
if (action.key) {
|
||||
const lastRouteIndex = state.routes.findIndex(
|
||||
r => r.key === action.key
|
||||
);
|
||||
if (lastRouteIndex !== -1) {
|
||||
// If index is unchanged and params are not being set, leave state identity intact
|
||||
if (state.index === lastRouteIndex && !action.params) {
|
||||
return state;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
});
|
||||
|
||||
// Remove the now unused routes at the tail of the routes array
|
||||
const routes = state.routes.slice(0, lastRouteIndex + 1);
|
||||
if (lastRouteIndex !== -1) {
|
||||
// If index is unchanged and params are not being set, leave state identity intact
|
||||
if (state.index === lastRouteIndex && !action.params) {
|
||||
return state;
|
||||
}
|
||||
|
||||
// Apply params if provided, otherwise leave route identity intact
|
||||
if (action.params) {
|
||||
const route = state.routes.find(r => r.key === action.key);
|
||||
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
|
||||
: undefined,
|
||||
index: lastRouteIndex,
|
||||
routes,
|
||||
// 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
|
||||
: undefined,
|
||||
index: lastRouteIndex,
|
||||
routes,
|
||||
};
|
||||
}
|
||||
|
||||
if (childRouter) {
|
||||
|
||||
@@ -520,7 +520,60 @@ describe('StackRouter', () => {
|
||||
expect(poppedImmediatelyState.isTransitioning).toBe(false);
|
||||
});
|
||||
|
||||
test('Navigate Pushes duplicate routeName', () => {
|
||||
test('Navigate does not push duplicate routeName', () => {
|
||||
const TestRouter = StackRouter(
|
||||
{
|
||||
foo: { screen: () => <div /> },
|
||||
bar: { screen: () => <div /> },
|
||||
},
|
||||
{ initialRouteName: 'foo' }
|
||||
);
|
||||
const initState = TestRouter.getStateForAction(NavigationActions.init());
|
||||
const barState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'bar' }),
|
||||
initState
|
||||
);
|
||||
expect(barState.index).toEqual(1);
|
||||
expect(barState.routes[1].routeName).toEqual('bar');
|
||||
const navigateOnBarState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'bar' }),
|
||||
barState
|
||||
);
|
||||
expect(navigateOnBarState.index).toEqual(1);
|
||||
expect(navigateOnBarState.routes[1].routeName).toEqual('bar');
|
||||
});
|
||||
|
||||
test('Navigate focuses given routeName if already active in stack', () => {
|
||||
const TestRouter = StackRouter(
|
||||
{
|
||||
foo: { screen: () => <div /> },
|
||||
bar: { screen: () => <div /> },
|
||||
baz: { screen: () => <div /> },
|
||||
},
|
||||
{ initialRouteName: 'foo' }
|
||||
);
|
||||
const initialState = TestRouter.getStateForAction(NavigationActions.init());
|
||||
const fooBarState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'bar' }),
|
||||
initialState
|
||||
);
|
||||
const fooBarBazState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'baz' }),
|
||||
fooBarState
|
||||
);
|
||||
expect(fooBarBazState.index).toEqual(2);
|
||||
expect(fooBarBazState.routes[2].routeName).toEqual('baz');
|
||||
|
||||
const fooState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'foo' }),
|
||||
fooBarBazState
|
||||
);
|
||||
expect(fooState.index).toEqual(0);
|
||||
expect(fooState.routes.length).toEqual(1);
|
||||
expect(fooState.routes[0].routeName).toEqual('foo');
|
||||
});
|
||||
|
||||
test('Navigate pushes duplicate routeName if unique key is provided', () => {
|
||||
const TestRouter = StackRouter({
|
||||
foo: { screen: () => <div /> },
|
||||
bar: { screen: () => <div /> },
|
||||
@@ -533,7 +586,7 @@ describe('StackRouter', () => {
|
||||
expect(pushedState.index).toEqual(1);
|
||||
expect(pushedState.routes[1].routeName).toEqual('bar');
|
||||
const pushedTwiceState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'bar' }),
|
||||
NavigationActions.navigate({ routeName: 'bar', key: 'new-unique-key!' }),
|
||||
pushedState
|
||||
);
|
||||
expect(pushedTwiceState.index).toEqual(2);
|
||||
|
||||
Reference in New Issue
Block a user