From 1b2983eaa9e3ec6487d0fcdc661424b312247656 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 30 Aug 2019 20:15:54 +0200 Subject: [PATCH] fix: handle route names change when all routes are removed (#86) --- packages/example/src/Screens/AuthFlow.tsx | 128 ++++++++++++++++++ packages/example/src/index.tsx | 5 + .../routers/__tests__/StackRouter.test.tsx | 62 ++++++++- packages/routers/src/StackRouter.tsx | 16 ++- 4 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 packages/example/src/Screens/AuthFlow.tsx diff --git a/packages/example/src/Screens/AuthFlow.tsx b/packages/example/src/Screens/AuthFlow.tsx new file mode 100644 index 00000000..4cbd937b --- /dev/null +++ b/packages/example/src/Screens/AuthFlow.tsx @@ -0,0 +1,128 @@ +import * as React from 'react'; +import { View, TextInput, ActivityIndicator, StyleSheet } from 'react-native'; +import { Title, Button } from 'react-native-paper'; +import { ParamListBase } from '@react-navigation/core'; +import { + createStackNavigator, + HeaderBackButton, + StackNavigationProp, +} from '@react-navigation/stack'; + +type AuthStackParams = { + splash: undefined; + home: undefined; + 'sign-in': undefined; +}; + +const SplashScreen = () => ( + + + +); + +const SignInScreen = ({ + setUserToken, +}: { + setUserToken: (token: string) => void; +}) => { + return ( + + + + + + ); +}; + +const HomeScreen = ({ + setUserToken, +}: { + setUserToken: (token: undefined) => void; +}) => { + return ( + + Signed in successfully 🎉 + + + ); +}; + +const SimpleStack = createStackNavigator(); + +type Props = { + navigation: StackNavigationProp; +}; + +export default function SimpleStackScreen({ navigation }: Props) { + const [isLoading, setIsLoading] = React.useState(true); + const [userToken, setUserToken] = React.useState( + undefined + ); + + React.useEffect(() => { + const timer = setTimeout(() => setIsLoading(false), 1000); + + return () => clearTimeout(timer); + }, []); + + navigation.setOptions({ + header: null, + }); + + return ( + ( + navigation.goBack()} /> + ), + }} + > + {isLoading ? ( + + ) : userToken === undefined ? ( + + {() => } + + ) : ( + + {() => } + + )} + + ); +} + +const styles = StyleSheet.create({ + content: { + flex: 1, + padding: 16, + justifyContent: 'center', + }, + input: { + margin: 8, + padding: 10, + backgroundColor: 'white', + borderRadius: 3, + borderWidth: StyleSheet.hairlineWidth, + borderColor: 'rgba(0, 0, 0, 0.08)', + }, + button: { + margin: 8, + }, + text: { + textAlign: 'center', + margin: 8, + }, +}); diff --git a/packages/example/src/index.tsx b/packages/example/src/index.tsx index fcbf1481..cef92dc2 100644 --- a/packages/example/src/index.tsx +++ b/packages/example/src/index.tsx @@ -23,6 +23,7 @@ import SimpleStackScreen from './Screens/SimpleStack'; import BottomTabsScreen from './Screens/BottomTabs'; import MaterialTopTabsScreen from './Screens/MaterialTopTabs'; import MaterialBottomTabs from './Screens/MaterialBottomTabs'; +import AuthFlow from './Screens/AuthFlow'; YellowBox.ignoreWarnings(['Require cycle:', 'Warning: Async Storage']); @@ -47,6 +48,10 @@ const SCREENS = { title: 'Material Bottom Tabs', component: MaterialBottomTabs, }, + 'auth-flow': { + title: 'Auth Flow', + component: AuthFlow, + }, }; const Drawer = createDrawerNavigator(); diff --git a/packages/routers/__tests__/StackRouter.test.tsx b/packages/routers/__tests__/StackRouter.test.tsx index a3adc610..de5210d3 100644 --- a/packages/routers/__tests__/StackRouter.test.tsx +++ b/packages/routers/__tests__/StackRouter.test.tsx @@ -138,7 +138,7 @@ it('gets state on route names change', () => { expect( router.getStateForRouteNamesChange( { - index: 0, + index: 2, key: 'stack-test', routeNames: ['bar', 'baz', 'qux'], routes: [ @@ -157,7 +157,7 @@ it('gets state on route names change', () => { } ) ).toEqual({ - index: 0, + index: 1, key: 'stack-test', routeNames: ['qux', 'baz', 'foo', 'fiz'], routes: [ @@ -166,6 +166,64 @@ it('gets state on route names change', () => { ], stale: false, }); + + expect( + router.getStateForRouteNamesChange( + { + index: 1, + key: 'stack-test', + routeNames: ['foo', 'bar'], + routes: [ + { key: 'foo-test', name: 'foo' }, + { key: 'bar-test', name: 'bar' }, + ], + stale: false, + }, + { + routeNames: ['baz', 'qux'], + routeParamList: { + baz: { name: 'John' }, + }, + } + ) + ).toEqual({ + index: 0, + key: 'stack-test', + routeNames: ['baz', 'qux'], + routes: [{ key: 'baz-test', name: 'baz', params: { name: 'John' } }], + stale: false, + }); +}); + +it('gets state on route names change with initialRouteName', () => { + const router = StackRouter({ initialRouteName: 'qux' }); + + expect( + router.getStateForRouteNamesChange( + { + index: 1, + key: 'stack-test', + routeNames: ['foo', 'bar'], + routes: [ + { key: 'foo-test', name: 'foo' }, + { key: 'bar-test', name: 'bar' }, + ], + stale: false, + }, + { + routeNames: ['baz', 'qux'], + routeParamList: { + baz: { name: 'John' }, + }, + } + ) + ).toEqual({ + index: 0, + key: 'stack-test', + routeNames: ['baz', 'qux'], + routes: [{ key: 'qux-test', name: 'qux' }], + stale: false, + }); }); it('handles navigate action', () => { diff --git a/packages/routers/src/StackRouter.tsx b/packages/routers/src/StackRouter.tsx index 98629da0..21b20fea 100644 --- a/packages/routers/src/StackRouter.tsx +++ b/packages/routers/src/StackRouter.tsx @@ -114,11 +114,25 @@ export default function StackRouter(options: StackRouterOptions) { }; }, - getStateForRouteNamesChange(state, { routeNames }) { + getStateForRouteNamesChange(state, { routeNames, routeParamList }) { const routes = state.routes.filter(route => routeNames.includes(route.name) ); + if (routes.length === 0) { + const initialRouteName = + options.initialRouteName !== undefined && + routeNames.includes(options.initialRouteName) + ? options.initialRouteName + : routeNames[0]; + + routes.push({ + key: `${initialRouteName}-${shortid()}`, + name: initialRouteName, + params: routeParamList[initialRouteName], + }); + } + return { ...state, routeNames,