Hiding specific tabs on react navigation bottomTabBarNavigation - reactjs

Imagine I have this structure for my tab bar:
const TabBarRoute = {
Home: HomeStack,
Orders: OrdersStack,
Trending: TrendingStack,
TopSelling: TopSellingStack
}
I want to show only three tabs (Orders, Trending, TopSelling) in my bottom tab navigator, How can I achieve it by react-navigation version 3.x ?
One idea that come to my mind is that I create a top stackNavigator and nest HomeStack along with my bottomTabNavigator inside of that and set the initial route of the top stackNavigator to the Home but problem with this approach is that it doesn't show the tab bar.

This example is using createBottomTabNavigator, but I imagine the same rules apply. It requires overriding the tabBarButtonComponent with a Custom component which returns null when the user doesn't have access to the given Tab.
const Config = {
allow_locations: true,
allow_stations: true
}
LocationsStackNavigator.navigationOptions = ({navigation}) => {
return {
tabBarLabel: 'Locations',
tabBarTestID: 'locations',
tabBarIcon: ({focused}) => (
<TabBarIcon
focused={focused}
name={'md-settings'}/>
)
}
};
const MyTabNav = createBottomTabNavigator(
{
LocationStackNavigator,
StationsStackNavigator,
OrdersStackNavigator,
SettingsStackNavigator
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarButtonComponent: CustomTabButton
})
}
);
class CustomTabButton extends React.Component {
render() {
const {
onPress,
onLongPress,
testID,
accessibilityLabel,
...props
} = this.props;
if(testID === 'locations' && !Config.allow_locations) return null;
if(testID === 'stations' && !Config.allow_stations) return null;
return <TouchableWithoutFeedback onPress={onPress} onLongPress={onLongPress} testID={testID} hitSlop={{ left: 15, right: 15, top: 5, bottom: 5 }} accessibilityLabel={accessibilityLabel}>
<View {...props} />
</TouchableWithoutFeedback>;
}
}

if you want to have dynamic items which they can change according to your situation you can do it in 2 ways :
first, you can declare a component as a parent of your react-navigation component then
create a store for your items and set them as #observable and change them whenever you want
declare your items as a state of your parent component and pass them to your react navigation
In these two solutions, every time your items change caused your component re-render with new values

Related

How to hide the navigation tab bar on a specific screen in react-navigation [duplicate]

I am using React Native and React Native Navigation to build out my application. Currently, I have three bottom tabs: Home, Upload Video and Messages. Upon selection of the Upload Video tab, I want to render the Upload Video component and hide the bottom tabs on just that screen, and display a header with 'Cancel' (takes them back to the HomeView) and 'Post' buttons (this has already been done). I've had an extremely difficult time hiding the tab bar on this specific screen.
I tried following the code here (How can I hide the bottom tab bar on a specific screen (react-navigation 3.x)); however, that ended up being unsuccessful and I was not able to hide the bottom tabs on any of the screens this way.
Currently, I have this as my bottom navigator:
const BottomTabNavigator = createBottomTabNavigator({
HomeView: {
screen: HomeView,
},
VideoView: {
screen: VideoSelectionView
},
Messages: {
screen: SearchView
}
});
Any insight would be extremely helpful, thanks.
I've traversed the internet like never before to find a solution for this problem as the provided solution by the docs did not work in the slightest.
I had the following navigational Set-Up:
Bottom Tabs
A (NativeStack)
1 (Screen)
2 (Screen)
3 (Screen)
B (NativeStack)
C (NativeStack)
I wanted to hide the bottom bar in Screen 1. What finally did the trick was the following snippet in the corresponding screen:
useEffect(() => {
navigation.getParent()?.setOptions({
tabBarStyle: {
display: "none"
}
});
return () => navigation.getParent()?.setOptions({
tabBarStyle: undefined
});
}, [navigation]);
The effect is run when the navigation prop updates and with that implicitly after the screen is being opened. With getParent() I get the bottom tabs navigator and can set the options with setOptions(...). To bring the bottom tabs back one has to manually set the options. I solved this by returning the method that resets the tabBarStyle in the call of useEffect(). This call is being made when it's time to clean-up, meaning that it will run as soon as the screen is being unmounted.
May this save same of you of the desperation I had to go through.
You need to specify for each TabBar screen or stack for which you need to hide tabbar,
const BottomTabNavigator = createBottomTabNavigator({
HomeView: {
screen: HomeView,
navigationOptions:()=>{
return {
tabBarVisible:false,
};
}
},
VideoView: {
screen: VideoSelectionView
},
Messages: {
screen: SearchView
}
});
on v5 you can modify options using a function and default arg navigation.:
<BottomTab.Screen
name="Explore"
component={Explore}
options={({ navigation }) => {
const { routes, index } = navigation.dangerouslyGetState();
const { state: exploreState } = routes[index];
let tabBarVisible = true;
if (exploreState) {
const { routes: exploreRoutes, index: exploreIndex } = exploreState;
const exploreActiveRoute = exploreRoutes[exploreIndex];
if (exploreActiveRoute.name === "RewardDetail") tabBarVisible = false;
}
return {
tabBarVisible,
title: "Explore",
tabBarLabel: "Explore",
tabBarIcon: ({ color, size }) => (
<AntDesign name="search1" color={color} size={size} />
),
};
}}
/>
see my answer: https://stackoverflow.com/a/64042879/5288560
Since react-navigation 5 is now being used, the above solution doesn't work anymore.
For React-Navigation 5, refer to this link.
In React Navigation V6 add display: none in options under tabBarStyle.
Add tabBarButton: () => null, to disable icon in Tab.
<Stack.Screen
name="Add Product"
component={AddProduct}
options={() => ({
tabBarStyle: {
display: "none",
},
tabBarButton: () => null,
})}
/>
Just setting the tabBarStyle to none doesn't work for me, I needed to use the property tabBarVisible too, if using hooks you can do something like that:
export function useHideBottomBar() {
const navigation = useNavigation();
useEffect(() => {
navigation.getParent()?.setOptions({ tabBarStyle: { display: 'none' }, tabBarVisible: false });
return () =>
navigation.getParent()?.setOptions({ tabBarStyle: undefined, tabBarVisible: undefined });
}, [navigation]);
}
In React navigation 5+ I used the following approach to hide a tab bar on a specific screen which was inside a stack navigator of a tab screen. In my tab navigator containing file I made a function, and then set the options property using the function which will trigger dynamically.
function getIsTabBarShown(route) {
const routeName = getFocusedRouteNameFromRoute(route) ?? routes.DASHBOARD;
switch (routeName) {
case routes.MEMBERDETAILS:
return false;
default:
return true;
}
}
This function will return false when user would go to MemberDetails Page which is inside MemberNavigator Stack.
<Tab.Screen
name="MemberTab"
component={MemberNavigator}
options={({ route }) => ({
title: 'Members',
tabBarVisible: getIsTabBarShown(route),
tabBarIcon: ({ color, size }) =>
<MaterialCommunityIcons name="account-group" color={color}
size={size} />
})} />
Here is the official docs to learn more click here.
Refer to the documentation by clicking here
After searching and trying a lot of methods I changed the top element View to Modal then hid bottombar, because modal can be upper bottom bar. It's not the best but still useful.
<View>
//code block
</View>
to->
<Modal animationType='fade' transparent={false} visible={true}>
/code block
</Modal>
In Version 6 this worked for me:
To hide the bottom tab navigator from the screen:
navigation.getParent()?.setOptions({tabBarStyle: {display: 'none'}});
To show the bottom tab navigator from the screen:
navigation.getParent()?.setOptions({tabBarStyle: {display: 'flex'}});
just on the Screen you want to hide the bar, set tabBarVisible: false.
<Tab.Screen
name="SignIn"
component={SignInScreen}
options={{
tabBarVisible: false, //like this
tabBarButton: (props) => null, //this is additional if you want to hide the tab element from the bottom nav
}}
/>

React Navigation 6 Hide Drawer Item

How can I hide screens from appearing as items in the drawer of #react-navigation/drawer version 6.
In React Navigation 5 it was achieved by creating custom drawer content like this
const CustomDrawerContent = (props: DrawerContentComponentProps) => {
const { state, ...rest } = props;
const includeNames = ["ScreenOne", "ScreenTwo"];
const newState = { ...state }; //copy from state before applying any filter. do not change original state
newState.routes = newState.routes.filter(
(item) => includeNames.indexOf(item.name) !== -1
);
return (
<DrawerContentScrollView {...props}>
<DrawerItemList state={newState} {...rest} />
</DrawerContentScrollView>
);
};
As was described in this other answer. I have just upgraded to react-navigation 6 and with this technique I get an error TypeError: Cannot read property 'key' of undefined when I try to navigate one of these hidden screen. Can anyone help me out?
Update - Solution Found
I found a solution by myself so will put it here for anyone else looking. Set the drawer item style display hidden like this:
<DrawerStack.Screen
name="ScreenName"
component={ScreenComponent}
options={{
drawerItemStyle: {
display: "none",
},
}}
/>

Custom back navigation for reactnavigation back button

How can I give a custom navigation to the header back arrow in ReactNavigation? I want the back arrow in the header to navigate to the screen I define and not to the previous screen.
Thanks.
You could try 2 things:
a) use headerMode: 'none' in your sub-StackRouters instead of your root router (named RouterComponent). Ideally you shouldn't have to do anything more then and the headers of the sub-StackRouters would be displayed in your root router's header. I think I remember something similarly worked a while back for me, but I haven't tested it in a while now and I think it's unlikely that it will still work like this but you can test nevertheless.
b) and this is what I'm currently using in a different situation. To manually include the back button:
import { HeaderBackButton } from '#react-navigation/stack';
const navigationOptions = ({ navigation }) => ({
headerLeft: <HeaderBackButton onPress={() => navigation.goBack(null)} />,
})
const RouterComponent = StackNavigator({
Tabs: {
screen: Tabs
},
Profile: {
screen: ProfileStack,
navigationOptions
}
},{
mode: 'modal',
headerMode: 'none',
});
If above solution doesn't work,
Try to add navigationOptions directly to the ProfileStack definition.
const ProfileStack = StackNavigator({
ProfileHome: {
screen: ProfileHome,
navigationOptions: ({navigation}) => ({ //don't forget parentheses around the object notation
title: 'Profile',
headerLeft: <HeaderBackButton onPress={() => navigation.goBack(null)} />
})
},
ProfileEdit: { screen: ProfileEdit }
}
Hi who ever is using react-navigation 5.x you might not be able to make navigation using navigationOptions. The option is been replaced with options.
Say your in screen -1 and navigated to screen-2 and then to screen-3. By default using react-navigation you can navigate from screen-3 to screen-2. But if you want customised navigation i.e., Say from above example if you want to navigate from screen-3 to screen-1.
If you would like to retain the view of back button and only override the onPress method, you can import { HeaderBackButton } from '#react-navigation/stack' and assign that component to the headerLeft option.
Example:
<RootStack.Screen
name="dashboard"
component={Dashboard}
options={({navigation, route}) => ({
headerLeft: (props) => (
<HeaderBackButton
{...props}
onPress={() => navigation.navigate('Home')}
/>
),
})}
/>
In above example on click of back button in Dashboard screen takes you to Home screen.
Enjoy & Thanks
-Sukshith

How to add a list count inside TabNavigator in react native

How to implement the count inside the tab navigator in react native.Below is the example image. I have asked react communities but nobody seems to have an answer for this.
Please Help.
You have two options here:
1.Use redux or something else so that your tab component knows its own count, regardless of the route.
2.You can have a param like badgeCount, which is visible because tabBar or any other navigation option can be defined as a function of the navigation prop:
static navigationOptions = {
tabBar: (navigation) => ({
label: 'Home',
icon: ({ tintColor, focused }) =>
<IconBadge
MainElement={
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
}
badgeNumber={navigation.state.params.badgeCount}
/>,
}),
}
Then you can change the param by calling navigation.setParams({ badgeCount: 123 }).
This has been addressed in this Github issue
In your Past Page:
static navigationOptions = ({navigation}) => ({
title: 'yourTitle',
tabBarLabel: 'Past${navigation.state.params.count}'
})
and it will display new count after you change the count by setParams method:
navigation.setParams({count: list.length})

React Navigation change Tab order programmatically

I'm creating an app with react-native with using react-navigation for routing. I know we can change tab order in react-navigation initially. But in my case, I need to change tab order programmatically. Is there any way to do that?
The following is an "almost pseudo code" example. It should at least drive you in the right direction. The trick is to use a "connected" main navigation component which reacts to changes in a redux store (in my case I stored the tabs order in a "settings" reducer) and force re-render of the tabs and their order, changing the screenProps property passed down by react-navigation to each navigator. Then there is a TabSelector component which returns the correct screen based on the props passed. I'm sorry if it's not totally clear what I mean but English is not my primary language :)
import Tab1 from 'app/components/Tab1';
import Tab2 from 'app/components/Tab2';
// ... all the imports for react-navigation
const TabSelector = (props) => {
switch(props.tab) {
case 1:
return <Tab1 {...props} />;
case 2:
return <Tab2 {...props} />;
}
};
const Tabs = {
PreferredTab: {
screen: ({ screenProps }) => (
<TabSelector tab={screenProps.firstTab} />
),
navigationOptions: ({ screenProps }) => ({
// write label and icon based on screenProps.firstTab
})
},
OtherTab: {
screen: ({ screenProps }) => (
<TabSelector tab={screenProps.otherTab} />
),
navigationOptions: ({ screenProps }) => ({
// write label and icon based on screenProps.otherTab
})
},
// other tabs...
};
const Navigator = createTabNavigator(Tabs, {
initialRouteName: 'PreferredTab',
// other options...
});
const WrappedNavigator = props => {
// fetch tab index from redux state, for example
const firstTab = useSelector(state => state.settings.firstTab);
const otherTab = useSelector(state => state.settings.otherTab);
return <Navigator screenProps={{ firstTab: firstTab, otherTab: otherTab }} {...props} />;
};
WrappedNavigator.router = Navigator.router;
export default createAppContainer(WrappedNavigator);

Resources