App Navigation state persisting EVEN IF app closed and restarted - react-native

I have a react-native app with two screens, Home and Details. Using react-navigation, Ive set the Stack navigator as following
const RootStack = createStackNavigator(
{
Home: FormComponent,
Details: DetailScreen
},
{
initialRouteName: "Home",
headerMode: "none"
}
);
Home contains a form, which once submitted, navigates to the Details screen with relevant data (using navigation.navigate("Details",{some data})). At this point, if I exit the app, and then open it again, the Details screen loads, with all the data preserved(Instead of the Home screen). I logged the navigation object data (this.props.navigation.) and it prints like the app was never closed.
Am I missing something here? Im new to React Native and Navigation, but from what I understand this is not expected behaviour.
Tried uninstalling app and rebuilding. This resets the app and Home screen loads. If I try reinstalling without uninstalling, back to same behaviour.
Tried also manually forcing navigation.goBack() on ComponentWillUnmount() but no difference.

This should've been a comment but sadly i don't have enough reputation.
Could you check if you haven't accidentally set a persistenceKey as a navigator prop?
https://reactnavigation.org/docs/en/state-persistence.html

Related

Building React Navigation v5 stack with Stack Navigation and Tab Navigation

I'm currently attempting to get my head round how to build out my React Navigation stack with v5, and not using a switchNavigator.
My basic app structure is such (will post an image of a flow below):
check Auth
-> signed in yes
-> tab navigation (with stack navigators nested within)
-> signed in no
-> nested stack navigator
But I just can't figure out how I should build the root of my app. I don't know how to combine my tab navigator and stack navigator together to make my app function from start to finish.
(It's worth noting, the 'check Auth' is an actual screen, not a conditional)
Here's my illustration showing my project layout:
Can someone advise please how I can build this out? Any tips or general structure / advice on how best to do it would be really appreciated!
So what I've typically done in the past is the render either or, not both. So as an example, the root navigation could look as follows:
import { NavigationContainer as RootNavigationContainer } from "#react-navigation/native";
const Navigation = () => {
const { someToken } = useContext(SomeContext);
return (
<RootNavigationContainer>
{!someToken ? <AuthStack /> : <MainStack />}
</RootNavigationContainer>
);
};
The determining of the user's authenticated state should be done while the Splash Screen is being shown, using a separate component just confuses the flow IMO. If the user is authenticated, you can set some state (in the example a token is set on the context) which will then drive which navigation stack is shown.
In my example, AuthStack would contain all of the screens where you user is unauthenticated - so your login, registration etc. MainStack would contain the screens that should only be shown to authenticated users.
Things like FaceID should be included in your Login flow.

React Navigation: How to fake a history in Stack Navigator?

I use https://reactnavigation.org/ and my app has a register process consisting of several screens:
First, the user has to enter his first name ("FirstNameView")
Second, the user has to enter his last name ("LastNameView")
...
If the user closes the app in the LastNameView and opens it later again, the app sends a request to the backend to fetch the current user data. Depending on this data, the user is navigated to the right screen via the initialRouteName property:
<MainStack.Navigator
initialRouteName="LastNameView"
>...
I have a back button on every screen which does navigation.goBack(), which obviously not works if the user just opens the app again and I direct him to the right View without pushing other screens to it.
One approach that I could think of is removing the navigation.goBack() functionality and replacing it with navigation.navigate("nameOfPreviousView"). However, this has the drawback that native "back" functionality of e.g. Android would not work.
How can I handle a case like this? Can I somehow create a fake history with my initialRouteName approach?
Yes you can create previous route history without navigating there.
In NavigationContainer initialize initialState like
let initialState = initialRoute = {
index: 1, // to load the second screen which is LastNameView
routes: [
{
name: 'FirstNameView',
},
{
name: 'LastNameView',
},
],
};
Like
<NavigationContainer initialState={initialState}> {/* ... */} </NavigationContainer>
To explore more about initialState check description here https://reactnavigation.org/docs/navigation-container/#initialstate

React Navigation error: not handled by any navigator

I realize why this occurring but am trying to figure out the best way to go about getting the required behavior:
Let's say I have a tab navigator and inside those tabs I have stack navigators. When I first open the app I am in the Home tab. Now let's say a push notification comes in and I handle that and say go to this screen in the profile stack navigator. The screen is not usually the first screen in the navigator but because I have not navigated to the profile screen via the tab navigator the initial screen is not loaded so it's the first in the stack. If I call navigation.pop it will not be handled by a navigator because their is no screen to go back to in the profile navigator.
I figured I could just call navigation.navigate('Profile') and it does navigate to that screen but it doesn't pop the initial screen so clicking the tab by default will now make the first screen the base screen until the app is restarted.
If I call navigation.goBack() I won't run into the above problem but I won't be able to always ensure that the 'Profile' screen is the place it goes back to.
Ideally I'd like some way to say push this screen into this stack and then push this screen. So when pop is called it will always show that users profile screen.
** EDIT **
After looking through some docs I found that I can do the following:
navData.dispatch(() => {
navData.navigate('Home', {
screen: 'ProfileScreen',
});
navData.navigate('Home', {
screen: 'ProfileScreen',
params: {
screen: 'ViewPostScreen',
params: { shouldPlay: true },
},
});
});
Though I get the following warning: Possible unhandled Promise rejection: TypeError: undefined is not an object 'action.target'
I'm also using this logic in another location of my app with a different screen and works in development but not in production. Looking for suggestions on to best handle the above situation.

Stack Navigation with tab and drawer navigation

Scenario:
After selecting the "Go To Detail" button, I would like to navigate to a new page without the bottom tab navigator.
Problem:
However, the bottom tab navigator is still there.
Possible solution:
Push the "DetailView" via the root view instead of "HomeView" stack. But how to do it?
Expo project link
Updated
Changed the Drawer Navigator to include DetailNavigator, however the transition is rather abrupt and it's added to drawer which is unwanted behavior:
const DrawerNavigator = createDrawerNavigator({
Home: BottomTabNavigator,
Settings: SettingsNavigator,
Detail: DetailNavigator
});
export const DetailNavigator = createStackNavigator({
Detail: { screen: DetailScreen }
});
After changing (DetailView appear abruptly):
Before changing (DetailView appear smoothly with animation):
you probably want to hide tab bar on specific screens without changing your navigators structure, take a look here https://reactnavigation.org/docs/en/navigation-options-resolution.html#a-tab-navigator-contains-a-stack-and-you-want-to-hide-the-tab-bar-on-specific-screens

React-native componentWillMount not calling

I am new in react-native I have two screens in my stack. Login and Home.
I want to go back to login from a button on home.
I am writing this code
this.props.navigation.navigate('loginScreen')
but in login screen componentWillMount method is not calling. I want to reset my form when user come on login screen from home.
Can anyone help me here?
Thanks in advance.
The this.props.navigation.navigate('loginScreen') don't work because you are now in loginScreen.
If you want to restart page this code isn't good. because have a loop!
correct code:
just when navigate to loginScreen from home use:
this.props.navigation.push('loginScreen')
NOT IN "componentWillMount"
To go back from login from home , you should use this.props.navigation.goBack() if the screen is immidiately before home.
Secondly, you should not use componentWillMount since it is deprecated and will be removed from React 17 onwards. Instead use componentDidMount
Since the component is already mounted therefore it won't call the react lifecycle events componentDidMount again. Therefore you should use the react-navigation listeners didFocus event.
didFocus: the screen focused (if there was a transition, the transition completed)
componentDidMount () {
this._onFocusListener = this.props.navigation.addListener('didFocus', (payload) => {
// Perform the reset action here
});
}
Since your Home and Login Screens are both under the same StackNavigator, when you go from Home back to Login the state stays the same as the component doesn't unmount. The recommended way to solve this is using the SwitchNavigator of react-navigation. Read this very helpful part of the documentation below
https://reactnavigation.org/docs/en/auth-flow.html
You may not be familiar with SwitchNavigator yet. The purpose of
SwitchNavigator is to only ever show one screen at a time. By default,
it does not handle back actions and it resets routes to their default
state when you switch away.
The perfect solution is with this.props.navigation.push('Login'), I tried with SwitchNavigator but it doesn't provide navigationOptions for header.