mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-03-06 22:39:41 +08:00
Prevent navigation from getting in bad state when navigating back to route by key (#3478)
This commit is contained in:
committed by
Eric Vicenti
parent
cca06bb530
commit
eb39df507e
@@ -25,6 +25,7 @@ import TabsInDrawer from './TabsInDrawer';
|
||||
import ModalStack from './ModalStack';
|
||||
import StacksInTabs from './StacksInTabs';
|
||||
import StacksOverTabs from './StacksOverTabs';
|
||||
import StacksWithKeys from './StacksWithKeys';
|
||||
import SimpleStack from './SimpleStack';
|
||||
import SimpleTabs from './SimpleTabs';
|
||||
import TabAnimations from './TabAnimations';
|
||||
@@ -76,6 +77,10 @@ const ExampleInfo = {
|
||||
name: 'Stacks over Tabs',
|
||||
description: 'Nested stack navigation that pushes on top of tabs',
|
||||
},
|
||||
StacksWithKeys: {
|
||||
name: 'Link in Stack with keys',
|
||||
description: 'Use keys to link between screens',
|
||||
},
|
||||
LinkStack: {
|
||||
name: 'Link in Stack',
|
||||
description: 'Deep linking into a route in stack',
|
||||
@@ -114,6 +119,9 @@ const ExampleRoutes = {
|
||||
ModalStack: {
|
||||
screen: ModalStack,
|
||||
},
|
||||
StacksWithKeys: {
|
||||
screen: StacksWithKeys,
|
||||
},
|
||||
StacksInTabs: {
|
||||
screen: StacksInTabs,
|
||||
},
|
||||
|
||||
97
examples/NavigationPlayground/js/StacksWithKeys.js
Normal file
97
examples/NavigationPlayground/js/StacksWithKeys.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import React from 'react';
|
||||
import { Button, StatusBar, Text, View } from 'react-native';
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
|
||||
class HomeScreen extends React.Component<any, any> {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Home</Text>
|
||||
<Button
|
||||
title="Navigate to 'Profile' with key 'A'"
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({
|
||||
routeName: 'Profile',
|
||||
key: 'A',
|
||||
params: { homeKey: this.props.navigation.state.key },
|
||||
})
|
||||
}
|
||||
/>
|
||||
<StatusBar barStyle="default" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileScreen extends React.Component<any, any> {
|
||||
render() {
|
||||
const { homeKey } = this.props.navigation.state.params;
|
||||
return (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Profile</Text>
|
||||
<Button
|
||||
title="Navigate to 'Settings' with key 'B'"
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({
|
||||
routeName: 'Settings',
|
||||
key: 'B',
|
||||
params: { homeKey },
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
title={`Navigate back to 'Home' with key ${homeKey}`}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({ routeName: 'Home', key: homeKey })
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsScreen extends React.Component<any, any> {
|
||||
render() {
|
||||
const { homeKey } = this.props.navigation.state.params;
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Settings</Text>
|
||||
<Button
|
||||
title={`Navigate back to 'Home' with key ${homeKey}`}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({ routeName: 'Home', key: homeKey })
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
title="Navigate back to 'Profile' with key 'A'"
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({
|
||||
routeName: 'Profile',
|
||||
key: 'A'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const Stack = StackNavigator(
|
||||
{
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
},
|
||||
Profile: {
|
||||
screen: ProfileScreen,
|
||||
},
|
||||
Settings: {
|
||||
screen: SettingsScreen,
|
||||
},
|
||||
},
|
||||
{
|
||||
headerMode: 'none',
|
||||
}
|
||||
);
|
||||
|
||||
export default Stack;
|
||||
@@ -243,7 +243,13 @@ export default (routeConfigs, stackConfig = {}) => {
|
||||
if (state.index === lastRouteIndex && !action.params) {
|
||||
return state;
|
||||
}
|
||||
const routes = [...state.routes];
|
||||
let routes = [...state.routes];
|
||||
|
||||
// If we are navigating backwards in the stack (via key) the other routes
|
||||
if (lastRouteIndex + 1 < routes.length) {
|
||||
routes = routes.slice(0, lastRouteIndex + 1);
|
||||
}
|
||||
|
||||
// Apply params if provided, otherwise leave route identity intact
|
||||
if (action.params) {
|
||||
const route = state.routes.find(r => r.key === action.key);
|
||||
|
||||
@@ -553,6 +553,37 @@ describe('StackRouter', () => {
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
test('Navigate backwards with key removes leading routes', () => {
|
||||
const TestRouter = StackRouter({
|
||||
foo: { screen: () => <div /> },
|
||||
bar: { screen: () => <div /> },
|
||||
});
|
||||
const initState = TestRouter.getStateForAction(NavigationActions.init());
|
||||
const pushedState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'bar', key: 'a' }),
|
||||
initState
|
||||
);
|
||||
const pushedTwiceState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'bar', key: 'b`' }),
|
||||
pushedState
|
||||
);
|
||||
const pushedThriceState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'foo', key: 'c`' }),
|
||||
pushedTwiceState
|
||||
);
|
||||
expect(pushedThriceState.routes.length).toEqual(4);
|
||||
|
||||
const navigatedBackToFirstRouteState = TestRouter.getStateForAction(
|
||||
NavigationActions.navigate({
|
||||
routeName: 'foo',
|
||||
key: pushedThriceState.routes[0].key,
|
||||
}),
|
||||
pushedThriceState
|
||||
);
|
||||
expect(navigatedBackToFirstRouteState.index).toEqual(0);
|
||||
expect(navigatedBackToFirstRouteState.routes.length).toEqual(1);
|
||||
});
|
||||
|
||||
test('Handle basic stack logic for plain components', () => {
|
||||
const FooScreen = () => <div />;
|
||||
const BarScreen = () => <div />;
|
||||
|
||||
Reference in New Issue
Block a user