Reputation: 321
a) User navigates to some screen B in app. Backgrounds the app.
b) User opens app --> app always opens to initialRouteName (Loading --> first screen in Tab Navigator "Screen A"). This is unexpected since was previously using on Screen B.
Similarly, when opening the app from a notification, the Loading route is called, which then directs to TabNavigator first screen. I think I could store navigation history, then check for prior screen state if opening from foreground in the "Loading" screen. For the notification case, I could store notification params on tap, then pull notification parameters from storage to direct user to that specific page. This seems super cumbersome, and I wonder if there is a better way.
//Navigator
const SwitchNavigator = createSwitchNavigator(
{
TabNavigator,
Auth,
Loading
},
{
initialRouteName: "Loading"
}
);
//Loading.js
componentDidMount() {
signedIn ? this.props.navigation.navigate(TabNavigator)
: this.props.navigation.navigate(Auth)
}
Upvotes: 1
Views: 1200
Reputation: 11
I've solved this issue using React Context. I store the current screen in a context object's property and when app returns to foreground, in the initial route, I get the value of the current screen from context and navigate to it.
Something like that:
// context.js
import { createContext } from 'react';
export const AppContext = createContext({
currentScreen: null,
});
// rootManager.js
import React, { useContext, useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import Loading from 'loading';
import ScreenA from 'screenA';
import ScreenB from 'screenB';
import ScreenC from 'screenC';
import { AppContext } from 'context';
const Stack = createStackNavigator();
function RootManager() {
const appContext = useContext(AppContext);
const [initialRoute, setInitialRoute] = useState('Loading');
// Initializing code ...
return (
<AppContext.Provider value={appContext}>
<NavigationContainer>
<Stack.Navigator initialRouteName={initialRoute} headerMode='none'>
<Stack.Screen name='Loading' component={Loading} />
<Stack.Screen name='ScreenA' component={ScreenA} />
<Stack.Screen name='ScreenB' component={ScreenB} />
<Stack.Screen name='ScreenC' component={ScreenC} />
</Stack.Navigator>
</NavigationContainer>
</AppContext.Provider>
);
}
export default RootManager;
// loading.js
import React, { useContext } from 'react';
import { AppContext } from 'context';
function Loading({ navigation }) {
const appContext = useContext(AppContext);
// Control code ...
const cacheResourcesAsync = async () => {
// Loading code ...
navigation.navigate(appContext.currentScreen || 'ScreenA');
};
return (
// Rendering code ...
);
}
export default Loading;
// screenA.js
import React, { useContext } from 'react';
import { AppContext } from 'context';
function ScreenA({ navigation }) {
const appContext = useContext(AppContext);
appContext.currentScreen = 'ScreenA';
// Control code ...
return (
// Rendering code ...
);
}
export default ScreenA;
// screenB.js
import React, { useContext } from 'react';
import { AppContext } from 'context';
function ScreenB({ navigation }) {
const appContext = useContext(AppContext);
appContext.currentScreen = 'ScreenB';
// Control code ...
return (
// Rendering code ...
);
}
export default ScreenB;
// screenC.js
import React, { useContext } from 'react';
import { AppContext } from 'context';
function ScreenC({ navigation }) {
const appContext = useContext(AppContext);
appContext.currentScreen = 'ScreenC';
// Control code ...
return (
// Rendering code ...
);
}
export default ScreenC;
Upvotes: 1