learningAngular
learningAngular

Reputation: 321

React-Navigation: Navigating to previously active screen when App foregrounded

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

Answers (1)

pferriol
pferriol

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

Related Questions