React navigation tab navigator - Always pass the same route params when pressing tab

Johnathan Simeroth

I'm new here! I'm working with react navigation, and I love it!... but... I've run into an issue that I figure is user error and not a bug.

What are the details of your problem?

I made a minimal example in a snack here: https://snack.expo.dev/@jsimeroth/userprofilenav

There's a navigation flow in my app where my initial route params no longer get passed to the component on tab navigator presses/clicks. This happens when I have a tab navigator nested inside a stack navigator, and I navigate to a non-tab stack screen then back to a tab screen.

Desired behavior

User 1 is the logged in user, so I would like to always navigate back to their profile when the profile tab is clicked, even after viewing another user's profile.

What can I do to achieve the desired behavior?

Actual behavior

Currently, after navigating to another user's profile page, there is no way to get back to user 1's profile. Clicking the profile tab just takes you back to the new user's profile.

Platform(s)

I've seen it on both web and ios, haven't tried others. For some reason, this snack doesn't run on ios though so try web.

What did you try?

I tried adding an event listener, but am probably doing that wrong because I could never get it to fire even when using a basic console.log. Something I haven't tried but considered was building my own tab navigator instead of using the pre-built material one, but I have a feeling that's not necessary.

Code

Code is a bit long to show the example, so check out the snack! But also adding it here just in case that's preferred.

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
import { Card, Button } from 'react-native-paper';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';

// make navigator components
const Tab = createMaterialBottomTabNavigator();
const Stack = createNativeStackNavigator();

// basic icon
function ColoredIcon(name, color) {
  return <Icon name={name} color={color} size={20} />;
}

// SCREEN COMPONENTS
// Tab navigator screens
export function Profile({navigation, route}) {
const user = route.params.userId
  return (
    <View style={styles.container}>
      <Text>This is user: {user}</Text>
      {user === 1 ? (
        <Text>
          User 1 is the logged in user and I would like to see this user's profile page whenever I click the profile bottom tab. {'\n\n'}
          However, navigate to the communities tab...
        </Text>
      ) : (
        <Text>
          So far so good, you're seeing the desired user's profile. But now there is no way to get back to the default/logged in/current user. {'\n\n'}
          TLDR: how do I make it so that clicking the profile tab always sends the userId I provided in the initial params, while still allowing the profile component to render other users if navigated to in a different way?
        </Text>
      )}
    </View>
  )
}

export function CommunityList() {
  const navigation = useNavigation();
  return (
    <View style={styles.container}>
      <Button 
        onPress={() => {
          navigation.navigate('Community', {community: 1})}
        }
        mode='contained'
      >
        See community 1
      </Button>
      <Text>
        Select a community...
      </Text>
    </View>
  )
}

// Stack screens
export function Community() {
  const navigation = useNavigation();
  return (
    <View style={styles.container}>
      <Button 
        onPress={() => {
          navigation.navigate('Profile', {userId: 2})}
        }
        mode='contained'
      >
        See user 2 profile
      </Button>
      <Text>
        This community has posts by different users. Click the above user to see their profile...
      </Text>
    </View>
  )
}

// Tab navigator (primary stack screen)
export function TabNav() {
  const userId = 1;
  return (
    <Tab.Navigator>
        <Tab.Screen
          name='Profile'
          component={Profile}
          initialParams={{ userId: userId }}
          options={{
            tabBarLabel: 'Profile',
            tabBarIcon: () => ColoredIcon('home', 'black'),
          }}
        />
        <Tab.Screen
          name='CommunityList'
          component={CommunityList}
          options={{
            tabBarLabel: 'Communities',
            tabBarIcon: () => ColoredIcon('account-group', 'black'),
          }}
        />
      </Tab.Navigator>
  );
}

// Stack navigator
export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name='TabNav' component={TabNav} />
        <Stack.Screen name='Community' component={Community} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
});

EDIT: updated to clarify the desired behavior

Johnathan Simeroth

Somebody on discord pointed me in the right direction on this one. By setting a tabPress listener on the profile tab you can specify the route params you want sent whenever the tab is pressed. This enables the desired behavior of always viewing the default user's profile whenever the profile tab is clicked.

In my case the code is:

          listeners={({ navigation }) => ({
            tabPress: (e) => {
              e.preventDefault();
              navigation.navigate('Profile', { userId: 1 });
            },
        })}

In context of the tab navigator component that looks like this:

// Tab navigator (primary stack screen)
export function TabNav() {
  const userId = 1;
  return (
    <Tab.Navigator>
        <Tab.Screen
          name='Profile'
          component={Profile}
          initialParams={{ userId: userId }}
          listeners={({ navigation }) => ({
            tabPress: (e) => {
              e.preventDefault();
              navigation.navigate('Profile', { userId: 1 });
            },
        })}
          options={{
            tabBarLabel: 'Profile',
            tabBarIcon: () => ColoredIcon('home', 'black'),
          }}
        />
// ... etc
      </Tab.Navigator>
  );
}

Hope this helps somebody else out there too!

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Passing params to tab navigator React Navigation 5

Get the current active screen route of the tab navigator in react navigation

Tab navigator icons in React Navigation

React Navigation How to pass to Tab navigator form Login Screen?

Passing Params from Stack-navigator to tab Navigator (react-navigation 5)

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

How to pass params from a stack navigator to a Material top tab navigator?

React Navigation: nesting stack and tab navigator

Leave screen callback React Navigation Tab Navigator

Cross fade animation in react navigation tab navigator

react navigation tab navigator inside static layout

React Native Pass Param From Drawer Navigator to Tab Navigator

Navigate to Tab Navigator from Stack Navigator with Params

React-navigation: header does not show up when using bottom tab navigator

React Navigation 5 pass params to screen inside nested navigator

How to unmount inactive screens in bottom tab navigator react-navigation?

React Navigation - wrapping header and tab navigator in Blurview looses props

Can react navigation add costom button on the tab navigator like the pictures

react-navigation change active tab from nested navigator

React navigation 5 hide tab bar from stack navigator

Are you able to programmatically generate screens inside React Navigation Tab Navigator

Custom navigation operation on specific tab button of react-navigation's tab navigator

React Navigation: Scroll to top if tab is the same as active tab

React Navigator 5; Tab Navigator and Stack Navigator

How to use react native navigation to create a nested navigation? (Example: Stack navigator inside a Tab navigator)

how to pass properties to a react-native component inside a tab navigator?

React bootstrap: How to enable tab navigation when using Tab component

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

React Navigation: How to go back to root Tab Navigator with specific tab from child stack

TOP Ranking

HotTag

Archive