How to set always first screen of Stack Navigator inside Tab Navigator React Navigation 5
Asked Answered
I

6

12

React Navigation 5

I've build a StackNavigator inside of a TabNavigator, and the navigation between home screen and other screens is working. But the problem is,When I move from Tab2 to Tab1 I expect Tab1 always show me first screen of StackNavigator.

tab1
   -> Stack
        -screen1
        -screen2
tab2

I am on screen2 and then move to tab2 after that then I move back to Tab1 I want to always display screen1.

I am try to use

OnTabPress({navigation})=>{
    navigation.navigate("stackName",{
     screen: "screen1"
   }).
}

Its work but its show me screen2 first then navigate to screen1. Is there any other Solution. https://snack.expo.io/@usamasomy/groaning-donut

Intent answered 28/4, 2020 at 19:28 Comment(0)
E
25

Use unmountOnBlur: true in options. Eg.

<Tab.Screen
        name="Stack1"
        component={Stack1}
        options={{
          tabBarLabel: "Stack1",
          unmountOnBlur: true,
        }}
      />

So when you are navigating away from this tab and you're on screen2 of Stack1, you will always come on the first screen of this stackNavigator when coming back to this tab.

Electropositive answered 4/11, 2020 at 19:36 Comment(0)
V
2

enter image description here

initialRouteName= "NAME" is the keyword to make sure you have a default and make sure you use navigate() push() pop() accordingly.

Firstly, create a custom TabBar so we can write our own functions executed by onPress

function MyTabBar({ state, descriptors, navigation }) {
  return (
    <View style={{ flexDirection: 'row' }}>
      {state.routes.map((route, index) => {
        const { options } = descriptors[route.key];
        const label =
          options.tabBarLabel !== undefined
            ? options.tabBarLabel
            : options.title !== undefined
            ? options.title
            : route.name;

        const isFocused = state.index === index;

        const onPress = () => {
            navigation.reset({
              index: 0,
              routes: [{ name: 'Screen1' }],
            }) 

        if (!isFocused && !event.defaultPrevented) {
            navigation.navigate(route.name);
          }      
            }}
        const onLongPress = () => {
          navigation.emit({
            type: 'tabLongPress',
            target: route.key,
          });
        };

Then in the TabScreens override the original TabBar in Tab.Navigator by using tabBar=... then call navigation.reset() with index:0 and routes:{{name: 'Screen1'}} every time MyTabBar is pressed.

const TabScreens = ()=>{
  return(
    <Tab.Navigator  tabBar={props => <MyTabBar {...props} />} initialRouteName="Tab1Screens" >
      <Tab.Screen 
        name      = "Tab1Screens"
        component = {Tab1Screens}
      />
      <Tab.Screen
        name      = "Tab2Screens"
        component = {Tab2Screens}
      />
    </Tab.Navigator>
  )
}

        return (
          <TouchableOpacity
            accessibilityRole="button"
            accessibilityStates={isFocused ? ['selected'] : []}
            accessibilityLabel={options.tabBarAccessibilityLabel}
            testID={options.tabBarTestID}
            onPress={onPress}
            onLongPress={onLongPress}
            style={{ flex: 1 }}
          >
            <Text style={{ color: isFocused ? '#673ab7' : '#222' }}>
              {label}
            </Text>
          </TouchableOpacity>
        );
      })}
    </View>
  );
}

This can be greatly improved eg:

-some logic before `navigation.reset()`

-Accessing onPress without creating a new component 

-etc..

finally snack available here :https://snack.expo.io/@karammarrie/customtabbar

Vernita answered 28/4, 2020 at 20:19 Comment(7)
First of All Im very Thankful for your kind response. InitialRouteName works only for first time.Then its Not working and Im unable to use Pop when I'm Moving from Screen1 -> Screen2. Is it Possible when I navigate to Screen2 like navigation.navigate("Screen2") before navigate to screen I will screen1 to Top of the stack and when I come from tab2 -> tab1 it will show me again screen1. Thanks.Intent
Thanks its working.But is there any other way in which we can achive this result without custom tabBar May be inside <Tab.screen listeners ={ ({navigation})=>({ tabPress: (e)=>{ e.preventDefault; *May be Here* } }) } />Intent
if it is working like you requested please accept the answer so others can find it useful. Anyway, i will make sure to check out what you suggested.Vernita
<Tab.Screen name="Stack1" component={Stack1} listeners ={ ({navigation})=>({ tabPress: (e)=>{ e.preventDefault; navigation.dispatch( navigation.reset({ index: 0, routes: [{screen: 'screen1'}] }) ) } }) } /> this code also give me same Result as your code witout changing tabbar style but one exception in boht code is that its always rerender the component. I will fetch some data from api and acording to to above code component rerender and data fetched again. how to accecpt your answer?Intent
This does! as you can see in my answer this can be greatly improved by accessing onPress without creating a new component.which is what you are doing with the listeners part. I personally like creating components so i have more control. If you scroll to the top of my answer there should be a checkbox next to the number to mark it accepted, do that (:Vernita
If you want to save the state without rerendering the API calls you will need some kind of saving states the most common way is Redux. offical docs: react-redux.js.orgVernita
Im really appreciate your response.You also Increase my knowledge.Thanks Again.Intent
F
1

There is no documentation about it, but the following code worked for me:

 const navigationComp = useNavigation<StackNavigationProp<Screen1Stack>();

 <Tab.Screen
    name="Screen1 Tab"
    component={Screen1StackScreen}
    listeners={{
          tabPress: () => {
            navigationComp.replace('Screen 1 Child 1');
          },
        }}
  />

The code above always navigates to the 'Screen 1 Child 1' when the "Screen1 Tab" is pressed.

Frangos answered 19/10, 2022 at 8:47 Comment(0)
S
1

Another option is to clear the stack of the navigation before navigating, so when you return to that screen, the navigation starts from the top

      navigation.dispatch(StackActions.popToTop());
      navigation.navigate("NextScreen");
Sammie answered 28/1, 2023 at 23:40 Comment(0)
A
0

i have a simple solution is to set initialRouteName= "screen1" in

<Stack.Navigator
      screenOptions={{
        headerShown: false,
      }}
      initialRouteName="screen1"
    >
      <Stack.Screen name="screen1" component={Screen1} />
      <Stack.Screen name="screen2" component={Screen2} />
</Stack.Navigator>

   {/** **/}

if the screen still shows the first screen 2, you just need to comment the line <Stack.Screen name="screen2" component={Screen2} /> and reload the screen, then remove the comment line.

Acerate answered 21/4, 2022 at 9:48 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Parish
M
0

like this

e

xport default function BottonTab() {
      const tabOffsetValue = useRef(new Animated.Value(0)).current;
      return (
        <View style={{flex: 1, backgroundColor: colors.primaryColor}}>
          <Tab.Navigator
            initialRouteName="Home"
            screenOptions={{
              showLabel: false,
              tabBarShowLabel: false,
              headerShown: false,
              tabBarStyle: {
                backgroundColor: colors.white,
                position: 'absolute',
                bottom: hp(0.51),
                marginHorizontal: wp(2),
                height: hp(8),
                borderRadius: wp(2),
                shadowColor: '#000',
                shadowOpacity: 0.06,
                shadowOffset: {
                  width: 10,
                  height: 10,
                },
                paddingHorizontal: 20,
              },
            }}>
            <Tab.Screen
              name={'Home'}
              component={HomeScreen}
              options={{
                title: 'Home',
                showLabel: false,
                tabBarIcon: ({focused}) => (
                  <View>
                    <FontAwesome5
                      name="home"
                      size={wp(6)}
                      color={
                        focused ? colors.primaryColor : colors.secondaryTextColor
                      }
                    />
                  </View>
                ),
              }}
              listeners={({navigation, route}) => ({
                tabPress: e => {
                  Animated.spring(tabOffsetValue, {
                    toValue: getWidth() * 0,
                    useNativeDriver: true,
                  }).start();
                },
              })}
            />
    
            <Tab.Screen
              name={'HelpDiskScreen'}
              component={HelpDiskScreen}
              options={{
                title: 'HelpDisk',
                tabBarIcon: ({focused}) => (
                  <View>
                    <FontAwesome5
                      name="search"
                      size={wp(6)}
                      color={
                        focused ? colors.primaryColor : colors.secondaryTextColor
                      }
                    />
                  </View>
                ),
              }}
              listeners={({navigation, route}) => ({
                tabPress: e => {
                  Animated.spring(tabOffsetValue, {
                    toValue: getWidth() * 1.22,
                    useNativeDriver: true,
                  }).start();
                },
              })}
            />
    
            <Tab.Screen
              name={'ManageBookingScreen'}
              component={ManageBookingScreen}
              options={{
                title: 'Manage',
                tabBarIcon: ({focused}) => (
                  <View>
                    <Feather
                      name="settings"
                      size={wp(6)}
                      color={
                        focused ? colors.primaryColor : colors.secondaryTextColor
                      }
                    />
                  </View>
                ),
              }}
              listeners={({navigation, route}) => ({
                tabPress: e => {
                  Animated.spring(tabOffsetValue, {
                    toValue: getWidth() * 2.52,
                    useNativeDriver: true,
                  }).start();
                },
              })}
            />
    
            <Tab.Screen
              name={'ParkyingTypesScreen'}
              component={ParkyingTypesScreen}
              options={{
                title: 'Parking',
                tabBarIcon: ({focused}) => (
                  <View>
                    <FontAwesome5
                      name="bell"
                      size={wp(6)}
                      color={
                        focused ? colors.primaryColor : colors.secondaryTextColor
                      }
                    />
                  </View>
                ),
              }}
              listeners={({navigation, route}) => ({
                tabPress: e => {
                  Animated.spring(tabOffsetValue, {
                    toValue: getWidth() * 3.82,
                    useNativeDriver: true,
                  }).start();
                },
              })}
            />
          </Tab.Navigator>
    
          <Animated.View
            style={{
              width: getWidth(),
              marginLeft: getWidth() * 0.58,
              height: 2,
              backgroundColor: colors.primaryColor,
              bottom: hp(7),
              borderRadius: 20,
              transform: [{translateX: tabOffsetValue}],
            }}></Animated.View>
        </View>
      );
    }
Madden answered 21/10, 2022 at 13:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.