How to navigate to a same screen on stack in react native - react-native

I have a stack in react-native-navigation. I want to navigate to a screen that is in the stack before.
but when I use Navigation.push command nothing happened and the screen does not change. How to implement this on react-native??
for exmaple my stakc is: [the part in the () does not navigate]
Main -> Map -> Stores (-> Map)
Note: I can't pop the screen to navigate to map. Because when I use the button that I Navigate with it, maybe the Map Screen doesn't in the stack. In the other word, some times I navigate from Main to Map and then to Stores, and some times I navigate to Stores from Main directly. and my button that is saying about to navigate to Stores screen in Map screen.

I finally found the solution.
Navigation.push or Navigation.pop is a promise that is made error when there is impossible to run command for any reason.
I use it and when Navigation.push made error in catch clause, I pop the screen.
For example:
Navigation.push('Map', {
component: {
id: 'Stroes',
name: 'Stroes',
options: {},
passProps: {},
},
}).catch(e => {
Navigation.pop('Stroes');
});

Related

Why does my state persist on screen change?

I am developing a React Native app and I am currently using a component in 2 different places of my app. I navigate from one place to another using a Drawer Navigator (React Navigation v6). This component updates a state when receiving a response from an API. However, if I switch to the other place where this component gets rendered, the state remains (therefore the visual message from the API appears inside it).
Why does this happen? Shouldn't all states reset on unmount and get the initial value (the one passed to useState()) when the component gets mounted again? This not the behavior I want and from what I know, this was not supposed to happen.
What can I do to make my state not persist on screen change? I have implemented the code below to be executed when a menu screen is selected, but has no effect on this issue:
navigation.dispatch(
CommonActions.reset({
index: 0,
key: null,
routes: [{ name: targetScreen }]
})
This behavior in react-native differs from react. This is documented here.
If you are coming to react-navigation from a web background, you may assume that when user navigates from route A to route B, A will unmount (its componentWillUnmount is called) and A will mount again when user comes back to it. While these React lifecycle methods are still valid and are used in react-navigation, their usage differs from the web.
Consider a screen A and a screen B. Suppose we navigate from A to B.
When going back from B to A, componentWillUnmount of B is called, but componentDidMount of A is not because A remained mounted the whole time.
This is valid for all navigators in react-native-navigation. Thus, if we have a tab bar navigation with 5 tabs, and each tab nests a Stack, then we could navigate on one stack to a certain depth, then switch the tab, and then switch the tab back again, and all screens visited will remain mounted.
Edit: In response to the comments. The recommended standard pattern to resolve your issue is as follows.
// some state in my component
const [state, setState] = useState()
useFocusEffect(
React.useCallback(() => {
// set state to initial value
setState()
}, [])
);
This is described here.
Your component does not unmount when you navigate out of component. Consider manually reseting your state inside this hook useFocusEffect

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.

I can't pass parameters using react-navigation in react-native while navigating from a tab navigator screen to a stack navigator screen

I think this is pretty straight forward when it comes to passing between screens of tab navigators but there seems to be a problem while trying to pass parameters from a tab navigator screen to a stack navigator screen in react-native using react-navigation.
I tried this:
onPress={() => {
this.props.navigation.navigate('review', {
aa1: 86,
bb1: 'anything you want here',
});
}}
And this:
onPress={() => this.props.navigation.dispatch(NavigationActions.navigate({ routeName: 'review', params: { aa1: 'x' }, }))}
as the onPress handler of my TouchableOpacity. None of them work. I can navigate but I can't get the params.
Below is how I try to get the parameters in the target stack navigator screen:
const { navigation } = this.props;
//if a is not passed, No a is the default value.
const a = this.props.navigation.getParam('aa1', 'NO a');
const b = navigation.getParam('bb1', 'No b');
Any ideas?
I was able to figure and solve the problem.
Problem was that name of the screen I was trying to navigate to and the name of the stack navigator (name of the stack navigator in the containing/parent tab navigator) that contained that screen was the same. And although navigation was working, the parameters were not being passed as I said in the problem description. Navigation was working because the screen that I was trying to navigate was set as the initial route in the containing stack navigator. Apparently, I was navigating and passing the parameters to the containing stack navigator. Once I changed the name of the stack navigator, the problem was solved.
Use navigation.push instead of navigation.navigate.
Reference: Oficial Docs.
I was facing the same problem, and i saw your own answer. The reason why this happens easily is that you are sending information to the stack, and not to the screens. As you can see in https://reactnavigation.org/docs/nesting-navigators, when you want to pass parameters to another screen inside a stack you need to specify the stack, then the screen and then the parameters, just like that:
navigation.navigate('Root', {
screen: 'Profile',
params: { user: 'jane' },
});
To be honest you can just put the parameters right with the screen, as in:
navigation.navigate('Root', {
screen: 'Profile',
user: 'jane',
});

Redirect screen in react native

I am using the stack navigator of react-navigator to build my project, I want to redirect the user to the home screen after the user signed in.
I am using navigation.navigate to redirect, but it will cause the home screen to display a back button to the login screen.
if (this.state.user) {
this.props.navigation.navigate('SignIn');
}
Is there any way to reset the navigation? or any other method I can perform without reset the navigation?
The way i would do it is to reset the navigation stack and then redirect it to the home page. Luckily there's a method for doing such thing called NavigationActions.reset which replace the navigation state with a new one.
So for your case i would do the following:
if (this.state.user) {
let newStack= NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Home'})
]
})
this.props.navigation.dispatch(newStack);
}
This code will create a new stack with the first page of the stack being the home page (you can change it with your custom routeName), and then use this new stack as our new navigation stack.
You can find more about the reset method on the official docs.
https://reactnavigation.org/docs/navigators/navigation-actions#Reset