Reset StackNavigator inside createBottomTabNavigator on tabBarOnPress - react-native

I have this structure:
bottomTabNavigator:
Screen 1
Screen 2
Screen A
Screen B
When the user navigates to Screen B, then goes to Screen 1 and go back to Screen 2, he goes directly in B, how can I reset the stack using the tabBarOnPress function to force the user to go back to A?
I'm using react-navigation 3.0.9, I tried a few codes but I got errors and I think it is due to the version.
My code structure:
const Navigator = createBottomTabNavigator({
Screen1: {
screen: Screen1,
navigationOptions: () => ({
tabBarOnPress...
})
},
Screen2: {
screen: Screen2,
navigationOptions: () => ({
tabBarOnPress...
})
}
})

In the new version, you can use the unmountOnBlur option for the screen. There is a little code sample:
<NavigationContainer>
<Tab.Navigator tabBarOptions={{
activeTintColor: ThemeConstants.mainColor,
}}>
<Tab.Screen name="Categories" component={CategoriesStackScreen}
options={{
unmountOnBlur:true
tabBarLabel: translate('Categories'),
tabBarIcon: ({color, size}) => (
<Icon style={[{color: color}]} type='MaterialIcons' name='restaurant-menu'/>
),
}}
/>
<Tab.Screen name="Info" component={InfoStackScreen}
options={{
unmountOnBlur:true,
tabBarLabel: translate('Info'),
tabBarIcon: ({color, size}) => (
<Icon style={[{color: color}]} type='MaterialIcons' name='info-outline'/>
),
}}
/>
<Tab.Screen name="Account" component={AccountStackScreen}
options={{
unmountOnBlur:true,
tabBarLabel: translate('Account'),
tabBarIcon: ({color, size}) => (
<Icon style={[{color: color}]} type='Feather' name='user'/>
),
}}/>
<Tab.Screen name="CartStackScreen" component={CartStackScreen}
options={{
unmountOnBlur:true,
tabBarBadge: (quantity && quantity>0)?quantity:null,
tabBarLabel: translate('Cart'),
tabBarIcon: ({color, size}) => (
<Icon style={[{color: color}]} type='Feather' name='shopping-cart'/>
),
}}
/>
</Tab.Navigator>
</NavigationContainer>
And there is the link that describes the property
https://reactnavigation.org/docs/bottom-tab-navigator/

So there is already a response, but this one could help some people. You can use the property of createBottomTabNavigator, resetOnBlur and set it up at true. It is in false at default and because of that, it always save the state in each tab navigator.

As given by the explanation here.
you can do a reset action when clicking a tab like this:
import { StackActions, NavigationActions } from 'react-navigation';
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Profile' })],
});
this.props.navigation.dispatch(resetAction);
So you should do something like:
tabBarOnPress{() => StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Screen1' })],
})};

Solution 1:
import { StackActions } from '#react-navigation/native';
if(this.props.navigation.canGoBack())
{
this.props.navigation.dispatch(StackActions.popToTop());
}
Solution 2:
use unmountonblur props in tab screen like this
<Tab.Navigator
>
<Tab.Screen
name='User'
component={ProfileModule}
options={{ unmountOnBlur: true }}
/>
</Tab.Navigator>

Related

React native reload bottom tabs on each click for webview

I have two bottom tabs 'Home' and 'Account' on the app and each one will load a webview of the website. When we click on the Home tab, it will load the website using the web view but if we go to the sub-items from that tab and then after clicking the Home tab again it doesn't change anything. I would like to go to the website's home page whenever a user clicks on the Home tab, Is it possible to do it? I tried using the unmountOnBlur: true option of the navigation and it's working if we are switching the different tabs but from the same tabs, it doesn't reload the page.
export default class App extends React.Component {
render() {
return (
<NavigationContainer>
<Tabs.Navigator
screenOptions={
{ headerShown: false }}
tabBarOptions={{
activeTintColor: '#000000',
inactiveTintColor: 'gray',
showLabel: false
}}
>
<Tabs.Screen name="Home" component={Home} options={{
unmountOnBlur: true,
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
listeners={({ navigation }) => ({
tabPress: (e) => {
// Prevent default action
e.preventDefault();
navigation.navigate("Home");
},
})}/>
<Tabs.Screen name="Account" component={Account} options={{
unmountOnBlur: true,
tabBarLabel: 'Profile',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account" color={color} size={size} />
),
}}
listeners={({ navigation }) => ({
tabPress: (e) => {
// Prevent default action
e.preventDefault();
navigation.navigate("Account");
},
})}/>
</Tabs.Navigator>
</NavigationContainer>
);
}
}

React native v6: tab bar customization

i have a bottom tab in my react native application, when i try to edit the tabBarStyle on the tab navigator it doesnt work. It only works on 1 out of my 3 tabs for some reason.
Only the help tab follows the required design the home and the test tab remain as default. I have tried all solutions only add made sure that i am using screenOptions and tabBarStyle instead of style.
const Tab = createBottomTabNavigator();
const AppNavigator = () => {
return (
<Tab.Navigator
screenOptions={{
tabBarActiveTintColor:'white',
tabBarLabelStyle:{
fontWeight:'700'
},
tabBarStyle: {
backgroundColor:'black',
borderTopColor: 'black',
elevation: 0, // for Android
shadowOffset: {
width: 0, height: 0 // for iOS
},
height:Platform.OS==='ios'&& dimen.width>400?80:Platform.OS==='ios'&& dimen.width<400?60:50,
}
}}
initialRouteName={"Home"}
>
<Tab.Screen
name="Home"
component={HomeNavigator}
options={{
tabBarIcon: ({ size, color,focused }) => (
<Entypo name="home" size={30} color={'#969696'}/>
),
headerShown:false,
unmountOnBlur: true,
}}
/>
<Tab.Screen
name="Test"
component={TestNavigator}
options={({ navigation }) => ({
tabBarButton: () => (
<NewListingButton
onPress={() => navigation.navigate(routes.test)}
/>
),
tabBarIcon: ({ size, color }) => (
<FontAwesome
name="life-saver"
size={size}
color={color}
/>
),
headerShown: false,
unmountOnBlur: true,
})
}
/>
<Tab.Screen
name="Help"
component={HelpNavigator}
options={{
tabBarIcon: ({ size, color,focused }) => (
<Ionicons name="help" size={30} color={'#969696'}/>
),
unmountOnBlur: true,
headerShown:false,
}}
/>
</Tab.Navigator>
)
};
export default AppNavigator;
My problem was with react navigation 6 in order to hide the tab navigator on specific screens i had to set the tabBarStyle display to none, which was why the background wasnt changing if the tab had a stack

When using both: Stack Navigator and BottomTab Navigator how do I hide the bottom tab when inside a Stack Navigation Screen?

I am having a Bottom Navigation with 2 Tabs so far (Home & Messages). When inside Messages I can press on a User to get navigated to the ChatScreen which is a Screen from the Stack Navigator. In that ChatScreen I want to hide the BottomTab. I know that it is possible to hide it by adding tabBarStyle: { display: "none" } to the <Tab.Screen /> but this doesn't work for the ChatScreen since it is not a Tab.Screen
import * as React from 'react';
import {View, Text} from 'react-native';
import {NavigationContainer, StackActions} from '#react-navigation/native';
import {createNativeStackNavigator} from '#react-navigation/native-stack';
import Home from './app/Screens/Home';
import CommentSection from './app/Screens/CommentSection';
import MessageScreen from './app/Screens/MessageScreen';
import ChatScreen from './app/Screens/ChatScreen';
import NavigationHeader from './app/global/headers/NavigationHeader';
import SendOffer from './app/Screens/SendOffer';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/MaterialIcons';
import ChatScreenHeader from './app/Screens/ChatScreen/ChatScreenHeader';
const HomeStack = createNativeStackNavigator();
const HomeStackScreen = () => {
return (
<HomeStack.Navigator initialRouteName="Home">
<HomeStack.Screen
name="HomeScreen"
component={Home}
options={{
// header: AppBar,
headerShown: false,
}}
/>
<HomeStack.Screen
name="CommentSection"
component={CommentSection}
options={{
headerTitle: 'Home',
// animationTypeForReplace: 'push',
animation: 'slide_from_bottom',
}}
/>
<HomeStack.Screen
name="SendOffer"
component={SendOffer}
options={{
headerTitle: 'Home',
animation: 'slide_from_right',
}}
/>
<HomeStack.Screen
name="ChatScreen"
component={ChatScreen} //HIDE BottomTab INSIDE THIS COMPONENT
options={{
headerTitle: 'Messages',
animation: 'slide_from_right',
}}
/>
</HomeStack.Navigator>
);
};
const MessageStack = createNativeStackNavigator();
const MessageStackScreen = () => {
return (
<MessageStack.Navigator>
<MessageStack.Screen
name="MessageScreen"
component={MessageScreen}
options={{
headerTitle: 'Messages',
animation: 'slide_from_right',
}}
/>
<MessageStack.Screen
name="ChatScreen"
component={ChatScreen} //HIDE BottomTab INSIDE THIS COMPONENT
options={{
headerTitle: 'Messages',
headerShown: false,
animation: 'slide_from_right',
}}
/>
</MessageStack.Navigator>
);
};
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator initialRouteName="Messages">
<Tab.Screen
name="Home"
component={HomeStackScreen}
options={{
headerShown: false,
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => (
<Icon name="home" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Messages"
component={MessageStackScreen}
options={{
headerShown: false,
tabBarLabel: 'Messages',
tabBarIcon: ({ color }) => (
<Icon name="chat" color={color} size={26} />
),
// tabBarStyle: { display: "none" }
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
Used solution by #Escaper from another question
useEffect(() => {
navigation.getParent()?.setOptions({ tabBarStyle: { display: "none" }});
return () => navigation.getParent()?.setOptions({ tabBarStyle: undefined });
}, [navigation]);
You could use createNavigationContainerRef to check the current route name via the getCurrentRoute() function inside the component that creates the BottomTabNavigator and then use tabBarStyle conditionally as you have suggested.
This could look as follows.
import { createNavigationContainerRef } from "#react-navigation/native"
const ref = createNavigationContainerRef();
const Tab = createBottomTabNavigator();
export default function App() {
const hide = "ChatScreen" === ref.current?.getCurrentRoute()?.name
return (
<NavigationContainer>
<Tab.Navigator initialRouteName="Messages">
<Tab.Screen
name="Home"
component={HomeStackScreen}
options={{
headerShown: false,
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => (
<Icon name="home" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Messages"
component={MessageStackScreen}
options={{
headerShown: false,
tabBarLabel: 'Messages',
tabBarIcon: ({ color }) => (
<Icon name="chat" color={color} size={26} />
),
tabBarStyle: { display: hide ? "none" : "flex" }
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}

React Native - Trying to create a drawer with tabs navigators in react navigation without the Drawer Item of the Tabs being rendered

I am trying to create an app where I have a drawer and tabs navigators on each page.
I followed various tutorials and the react navigation docs but could not find a solution.
I have created a drawer navigator and within the <drawer.screen/> component I put my main tab navigator (My Tab navigator has multiple stacks - HomeStack, JoinStack, etc). So far so good however when I navigate to that main tab label in the menu, I return to the same screen I came from last and not to the top of my HomeStack although the "initialRouteName" is set to "Home".
I decided to leave it but remove the label, however it does not remove it completely. It removes the text but still there is a component being rendered there (see Image1 below)
Image1:
DrawerItem still being rendered
DrawerNavigator.js
//imports and stuff
const Drawer = createDrawerNavigator();
function MyDrawer({logout}) {
const nav = useNavigation()
return (
<Drawer.Navigator
initialRouteName={stackNavigationsConsts.HOME_STACK}
drawerPosition="right"
drawerContent={(props) => {
return (
<CustomDrawer nav={nav} drawerProps={props}/>
)
}}
>
<Drawer.Screen name={"בדיקה"} component={MainTabNavigator} options={{drawerLabel: () => null}}/>
<Drawer.Screen name="מאמר" component={Article} />
</Drawer.Navigator>
);
}
MainTabNavigator.js
//imports and stuff
const Tab = createBottomTabNavigator();
export default function MainTabNavigator() {
return (
<Tab.Navigator
initialRouteName={stackNavigationsConsts.HOME_STACK}
tabBarOptions={{
activeTintColor: mainColor.secondaryColor,
inactiveTintColor: mainColor.text,
activeBackgroundColor: mainColor.MainBackgroundColor,
// activeBackgroundColor: mainColor.buttonPress,
inactiveBackgroundColor: mainColor.MainBackgroundColor,
keyboardHidesTabBar: true,
}}
>
<Tab.Screen name={stackNavigationsConsts.HOME_STACK} component={HomeStackScreens}
options={{
tabBarLabel: navigationConsts.HOME,
tabBarIcon: ({ color, size }) => (
homeIcon(color)
),
}}
/>
<Tab.Screen name={stackNavigationsConsts.PROFILE_STACK} component={AnotherStack2Screen} options={{
tabBarLabel: navigationConsts.PROFILE ,
tabBarIcon: ({ color, size }) => (
profileIcon(color)
),
}}/>
<Tab.Screen name={stackNavigationsConsts.JOIN_STACK} component={JoinStackScreens}
options={{
tabBarLabel: navigationConsts.JOIN ,
tabBarIcon: ({ color, size }) => (
JoinIcon(color)
),
}}/>
<Tab.Screen name={stackNavigationsConsts.NOTIFICATIONS_STACK} component={AnotherStackScreen} options={{
tabBarLabel: navigationConsts.NOTIFICATIONS ,
tabBarIcon: ({ color, size }) => (
messagesIcon(color)
),
tabBarBadge: 12
}}/>
<Tab.Screen name={stackNavigationsConsts.ADD_RIDE_STACK} component={AnotherStack1Screen} options={{
tabBarLabel: navigationConsts.ADD_RIDE ,
tabBarIcon: ({ color, size }) => (
addRideIcon(color)
),
}}/>
</Tab.Navigator>
);
}
I found the solution here - How to hide Drawer Item from Drawer #2021 There is a workaround from v5 onward, need to extract the list of routes from the drawer navigation state and filter out the label you don't want to as I understood and it worked perfectly!
Please see below my render function for the custom drawer:
render() {
const {state, ...rest} = this.props.drawerProps
const newState = {...state}
newState.routes = newState.routes.filter((item) => item.name !== "זמני")
return (
<DrawerContentScrollView {...this.props}
>
<View style={styles.avatar}>
<View style={styles.imageContainer}>
<Image style={styles.image} source={require('../../../assets/images/man_smile.png')}/>
<Text style={{...styles.text, fontSize:22, marginTop:5}}>גלעד דהן</Text>
</View>
</View>
<View style={styles.items}>
<DrawerItemList
state={newState}
{...rest}
/>
<DrawerItem label={navigationConsts.MAIN} onPress={() => this.props.nav.navigate(stackNavigationsConsts.HOME_STACK)} labelStyle={styles.text}/>
<DrawerItem label="התנתק" onPress={() => this.props.logout()} labelStyle={styles.text}/>
</View>
</DrawerContentScrollView>

React Native Navigation 5 - How to set a color for each bottom tab

I'm trying to setup a different color for each bottom tab on RNN 5.
const MyTab = createBottomTabNavigator();
<MyTab.Navigator>
<MyTab.Screen
name='ToTimerScreen'
component={TimerScreen}
options={({ route }) => ({
tabBarLabel: 'Timer',
tabBarIcon: () => TimerIcon(),
})}
/>
<MyTab.Screen
name='ToJournalScreen'
component={JournalScreen}
options={{
tabBarLabel: 'Journal',
tabBarIcon: () => JournalIcon(),
}}
/>
</MyTab.Navigator>
for example one blue and one red.
I tried every possible option but no way.
Someone knows how to?
Thanks!
Found it!
Just use Material Bottom Tab Navigator
import {createMaterialBottomTabNavigator} from '#react-navigation/material-bottom-tabs';
const MyTab = createMaterialBottomTabNavigator();
Example of a tab screen using tabBarColor: '#color'
<MyTab.Screen
name='ToJournalScreen'
component={JournalScreen}
options={{
tabBarColor: Colors.Journal, // this gives the color
tabBarLabel: 'Journal',
tabBarIcon: () => <Icon name={'md-book'} color={'red'} size={20} />,
}}
/>
Works in Android and iOS.
You can pass color props to Icon Component
import Icon from "react-native-vector-icons/Ionicons";
const MyTab = createBottomTabNavigator();
<MyTab.Navigator>
<MyTab.Screen
name="ToTimerScreen"
component={TimerScreen}
options={({route}) => ({
tabBarLabel: 'Timer',
tabBarIcon: ({focused}) => <Icon name={'iconName'} color={'blue'} size={24}/>,
})}
/>
<MyTab.Screen
name="ToJournalScreen"
component={JournalScreen}
options={{
tabBarLabel: 'Journal',
tabBarIcon: () => <Icon name={'iconName'} color={'red'} size={24}/>,
}}
/>
</MyTab.Navigator>