React navigation weird back button and pop behavior - react-native

I have a nested navigator in my react native App
cost Main = createTabNavigator({
Home:Home,
Challenge:Challenge,
Products:Products,
Options:Options
})
const Options = createStackNavigator({
OptionsScree:OptionsScreen,
Details:Details,
Profile:Profile
})
I can navigate from Home screen to Details by simply doing this.props.navigationnavigate('Details')
but when I'm doing this.props.navigation.pop()
it is supposed to take me to last focused screen which was Home screen but it takes me to OptionsScreen
is there a way to go back to Home ?

Try moving Main tab navigator component into stack navigator as below.
const Options = createStackNavigator({
Main:Main,
OptionsScree:OptionsScreen,
Details:Details,
Profile:Profile
})
As Home screen is not present in stack, this.props.navigation.pop() can not pop that screen for you. It pops previous screen in the stack, if none pops the first screen which is in your case is OptionsScreen.

Related

Make all tab bar buttons unfocused on specific screens

I have a react native app which uses react navigation (V6.x for sure). My app has a main navigator which is a bottom-tabs navigator and contains three screens (tabs). Every one of these screens are stack navigators themselves. Let's say one of my tabs is named Wallet (others are Settings and Transactions). Inside this Wallet screen (which is a stack navigator), i have a HomePage screen, a Receive screen and a Send screen. I want to achieve the following behavior (like below screenshot from designs):
Whenever the user goes to one of Send or Receive screens, i want all the tab bar buttons become unfocused (tab bar is still visibe though). And whenever the user gets back to HomePage screen (or going to Settings or Transactions tab by pressing the corresponding tab button), I want the relevant tab button to get focused again. How can i achieve that with react navigation itself?
(My project is managed by redux, but i prefer not to use state management tools and use react navigation itself)
You can do that, but checking child navigation state inside your TabNavigator's screenOptions.
screenOptions={({ route, navigation }) => {
// get wallet stack route
const walletStack = navigation.getState().routes.find((route) => route.name === 'Wallet');
// get current wallet stack focused screen
const walletRouteName = getFocusedRouteNameFromRoute(walletStack);
const shouldBeUnfocused =
walletRouteName === 'Send' || walletRouteName === 'Receive';
{...}
}
Based on shouldBeUnfocused you can render proper icons and colors. Here is the snack with example code. You can red here about customizing tab bar's appearance.

How to goBack globally between stacks in React Navigation?

I am using react navigation ("#react-navigation/native": "^5.1.3") and I have the following setup:
BottomNavigation
-stack1
-stack2
It looks like goBack() is local to the stack. What that means is that if I navigate from a page in stack1 to a page in stack2, I am unable to go the the page I came up from.
Solutions (or rather hacks) that didn't work for me:
pass the source screen as param and then navigate. That isn't a real back button and does not play well with android back button.
Put all pages in bottom navigation. Bottom navigation does not have animations it seems, so I can not achieve the right transitions
Put all pages in stack navigation. In this case I lose the fixed bottom navigation. I can add it to each page, but when transitioning it will go away with the old screen and come again with the new one, which is undesirable.
So I am wondering if I am missing something big here, like a globalBack() that I overlooked?!
And also, I am looking for a solution to this problem which remains.
Naturally if you have bottoms tabs with each tab having its own stack navigator, calling navigation.goBack() will go back from one screen inside stack navigator to previous screen inside that same stack navigator. That's how navigation works in pretty much every app. Pressing back button or swiping back does not change tab for you, tabs are more like separate small apps by itself. If you want to specifically jump from one tab to another instead of going back in stack, use navigation.dispatch(TabActions.jumpTo('Profile')). If pressing something inside tab#1 makes you go to to tab#2 then this screen most likely also belongs to tab#1
also, take a look at backBehavior prop of Tab.Navigator, it might be doing what you want depending on what exactly it is you want https://reactnavigation.org/docs/bottom-tab-navigator/#backbehavior
I'm using bottom tab navigator with 2 stacks as well. I faced similar issue and agree with #Max explanation. Due to my Notification screen is in Stack 1, I have to goBack to Notification after navigating away to Detail screen. After searching for the fix, I'm using this workaround (for v6).
Tab 1 - Stack 1 (Home > Notification screen)
Tab 2 - Stack 2 (Reward Home > Reward Detail screen)
I passed a param when navigating from Notification to RewardDetail. Then I override the headerLeft and use BackHandler to handle Android back function.
Notification.js
navigation.navigate('RewardStack', {
screen: 'RewardDetail',
initial: false,
params:{notification: notification_data_source}
})
RewardDetail.js
const payload = route.params.notification
//1. override headerLeft button
useLayoutEffect(() => {
if(payload)
navigation.setOptions({
headerLeft: () => (
<Button
TouchableComponent={TouchableOpacity}
buttonStyle={{paddingTop:4, paddingLeft:0}}
type='clear'
icon={<Icon name={'chevron-left'} size={30} style={{color:'#FFF'}} />}
onPress={()=>{
navigation.goBack()
navigation.navigate('Notification') //can use this only
}}
/>
)
})
}, [navigation]);
//2. Add BackHandler
useEffect(() => {
const onBackPress = () => {
if (payload) {
navigation.goBack()
navigation.navigate('Notification') //can use this only
return true
} else {
return false
}
}
BackHandler.addEventListener('hardwareBackPress', onBackPress)
return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress)
}, [navigation]);
I can just use navigation.navigate('Notification') to return to Notification but this will cause Detail screen to stay mounted in Stack 2. I want the Stack 2 to return to RewardHome after go back to Notification. Hence I used:
navigation.goBack() //pop screen to RewardHome
navigation.navigate('Notification') //jump to Notification

How to navigate from child tab to parent tab in native base tabs?

The scenario is like I have a native base tab, where I have 4 tabs. In the second tab, I have a children tab, which has 4 more tabs. What I need is I need to navigate to the parent tab's first tab, when the button is clicked on any of the children's tabs. I just tried to navigate using this.props.navigation.navigate('tab'), but it wasn't successful. Can anyone suggest some way to solve this? Thank you.
I think you should create stack with 4 tab child. create bottomTabbar with 4 tab parent. and nest stack to bottomTab.
For example stack
export const AssignStack = createStackNavigator({
Assign,
Search,
SearchResults,
TaskList,
TaskElement,
TaskDetail,
}
For example BottomTab
const TabNavigator = createBottomTabNavigator({
Mine: MineStack,
Assign: AssignStack,
Related: RelatedStack,
Chatting: ChatStack,
Notify: Notify,
Setting: SettingStack
}
In your stack, You can use this.props.navigation.navigate('MineStack').
Sorry for the presentation and my English not good. Hope help you

Nagivating to different screen does not call any function

I am using react navigation to create a drawer in my application. I noticed this occurrence when navigating to different screen.
Let's say I have this stack in my app :
Stack A
Stack B
Stack C
When I am at the Stack A and will navigate to Stack B for the first time enter, Stack B will read the componentDidMount() and here I will set a state (which is to connect to rest server to call out data from database).
From the Stack B, I will navigate to Stack C for the first time enter too and it works fine by reading the componentDidMount() too. Then I made some changes from Stack C (example: deleting data) which will affect the data in Stack B.
Now I am from Stack C and navigate back to Stack B (enter for the second time) but it won't read the componentDidMount() anymore. And so, my data will not be updated until I pull down the screen to refresh it.
How should I make the screen be able to read the componentDidMount() every time when enter to the screen?
What you need in this case is to listen to NavigationEvents because the components are already mounted, but didFocus will be called each time the view get the focus.
Here's an example code from the docs:
import React from 'react';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
const MyScreen = () => (
<View>
<NavigationEvents
onWillFocus={payload => console.log('will focus',payload)}
onDidFocus={payload => console.log('did focus',payload)}
onWillBlur={payload => console.log('will blur',payload)}
onDidBlur={payload => console.log('did blur',payload)}
/>
{/*
Your view code
*/}
</View>
);
export default MyScreen;
This is what stack navigator does, it want again load whole screen.
It just stores everything for you so that when you navigate back everything is there in whatever state you left the screen.
For example, you scrolled to half on particular screen and navigated to other screen,
now you came back and you will find your screen half scrolled where you left.
so it will do nothing when you came back.
Note: If screen is navigated in past and exist in current stack then navigating to screen again will not call any lifecycle methods.
So for your case,
you can pass a method reference to navigation params. and call it before you navigate.
like this,
let say you are in screenB and wanna call a method methodSuperCool=()=>{...} which resides in screenA from which you navigated to current screen.
for this you will have to pass method reference in params when you navigate to screenB from screenA.
this.props.navigation.navigate('screenB',{methodSuperCool:this.methodSuperCool});
//this to be write in screenA
now in screenB before you naviagte to screenA call this,
this.props.navigation.state.params.methodSuperCool() // this can also have params if you like to pass
this.props.navigation.navigate('screenA') // or goBack() method will also work
Navigating back from Stack C to Stack B wont call componentDidMount() as the components were already mounted when Stack B was first created.
you can do is reset the navigation stack when navigating from Stack B to Stack C like this
const stackCAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'StackC' })],
});
dispatching with
this.props.navigation.dispatch(stackCAction);
note going back wont be possible doing this.
alternately you can pass a callback function from Stack B to Stack C to refresh.
Check this link for full answer.

Cannot properly navigate between two different stacks in react native and keep back functionallity

Currently these are my screens in my react native app.
Root Nav - (SwitchNavigator)
Stack A - (BottomTabNavigator)
Page A
Page B
Stack B - (StackNavigator)
Page C
Page D
I am trying to navigate to page C/D From pages A/B But when I try to navigate using this.props.navigation.navigate() It will navigate correctly, but the history functionality such as swiping right or calling goBack() to go to the previous page (in a different stack) does not work.
When navigating to page D and swiping right, it goes to page C and swiping right again does not do anything.
Different stacks are meant to stand on their own, so if what you need is to keep the navigation history between those screens, you have to set them up in the same stack. Stacks can be set up in your flow just like screens, for example, setting up a stack navigator inside a drawer navigator:
/**
* User drawer stack
*/
const DrawerStack = DrawerNavigator({
Home: {screen: HomeStack}, //HomeStack is a StackNavigator
}, {
contentComponent: DrawerContainer,
initialRouteName: 'Home',
});
With this rethink what you want your history like. If I understood your use case correctly, you want A/B to share history with C/D, I'd say you need your stack to be like:
Root Nav - (SwitchNavigator)
Stack B - (StackNavigator)
Stack A - (BottomTabNavigator)
Page A
Page B
Page C
Page D
If you can't do that for some reason, then you will need to capture back presses and swipes manually to do the behavior yourself.