I have a mobile app where i switch tabs from tab navigator
I want to add a debounce with useDebouncedCallback hook because I want to prevent user from clicking tabs constantly.
How can I add this to the navigator ? I tried with listeners prop (tabPress) and onPress on TabBarButton but doesn't work
// name={NAVIGATION.FRIENDS}
name="Friends"
component={Friends}
// listeners={{
// tabPress: e => {
// debouncedUpdate(() =>
// NavigationService.navigate(NAVIGATION.FRIENDS),
// );
// },
// }}
options={{
tabBarLabel: strings.tab.friend,
tabBarIcon: ({focused, color, size}) => (
<TabBarButton
routeName={strings.tab.friend}
focused={focused}
color={color}
onPress={debouncedUpdate(() =>
NavigationService.navigate(NAVIGATION.FRIENDS),
)}
/>
),
}}
/>
Below is the full Tab Navigator codes
import React from 'react';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import {TabBarButton} from '#/components/TabBarButton';
import Home from '#/screens/dashboard/home/Home';
import Friends from '#/screens/dashboard/friends/Friends';
import ChatThreads from '#/screens/dashboard/chat/chat_threads/ChatThreads';
import Profile from '#/screens/dashboard/profile/Profile';
import {
whiteColor,
primaryBgColor,
tabInactiveTintColor,
tabActiveTintColor,
} from '#/config/colors';
import {COMMON, NAVIGATION} from '#/constants';
import {strings} from '#/localization';
import {Host} from 'react-native-portalize';
import {useSelector} from 'react-redux';
import {useDebouncedCallback} from 'use-debounce';
const Tab = createBottomTabNavigator();
const TabNavigator = () => {
const newMessagesCount = useSelector(state => state.chat.newMessagesCount);
const debouncedUpdate = useDebouncedCallback(fn => {
fn();
}, 200);
return (
<>
<Host>
<Tab.Navigator
tabBarOptions={{
activeTintColor: tabActiveTintColor,
inactiveTintColor: tabInactiveTintColor,
showLabel: false,
style: {height: COMMON.BOTTOM_TAB_BAR_HEIGHT},
}}>
<Tab.Screen
name={NAVIGATION.HOME}
component={Home}
options={{
tabBarLabel: strings.tab.home,
tabBarIcon: ({focused, color, size}) => (
<TabBarButton
routeName={strings.tab.home}
focused={focused}
color={color}
/>
),
}}
/>
<Tab.Screen
name={NAVIGATION.FRIENDS}
component={Friends}
options={{
tabBarLabel: strings.tab.friend,
tabBarIcon: ({focused, color, size}) => (
<TabBarButton
routeName={strings.tab.friend}
focused={focused}
color={color}
/>
),
}}
/>
<Tab.Screen
name={NAVIGATION.CHAT_THREADS}
component={ChatThreads}
options={{
tabBarBadge:
newMessagesCount > 99 ? '99+' : String(newMessagesCount),
tabBarBadgeStyle: [
{
backgroundColor: primaryBgColor,
height: 20,
minWidth: 20,
borderRadius: 10,
color: whiteColor,
fontSize: 10,
left: 5,
opacity: newMessagesCount ? 1 : 0,
},
],
tabBarLabel: strings.tab.chat,
tabBarIcon: ({focused, color, size}) => (
<TabBarButton
routeName={strings.tab.chat}
focused={focused}
color={color}
/>
),
}}
/>
<Tab.Screen
name={NAVIGATION.PROFILE}
component={Profile}
options={{
tabBarLabel: strings.tab.profile,
tabBarIcon: ({focused, color, size}) => (
<TabBarButton
routeName={strings.tab.profile}
focused={focused}
color={color}
/>
),
}}
/>
</Tab.Navigator>
</Host>
</>
);
};
export default TabNavigator;
Related
I don't seem to have any problems using setState in other pages of my project but in the app.js it just does not work? I am very new to react native.
I am calling the function 'handleacount' from another page and it gets the data and I just want to update the 'Acount'
The state is updating because it alerts but it does not update when it has already been rendered? Am I missing something?
The page App.js is :
import 'react-native-gesture-handler';
import React, { useState, Component } from "react";
import { MaterialCommunityIcons } from '#expo/vector-icons';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import Constants from 'expo-constants';
import IconBadge from 'react-native-icon-badge';
import { Text, View, StyleSheet } from 'react-native';
import HomeScreen from './pages/HomeScreen';
import SearchScreen from './pages/SearchScreen';
import SettingsScreen from './pages/SettingsScreen';
import MapScreen from './pages/MapScreen';
import NotificationsScreen from './pages/NotificationsScreen';
import { ListItem, Avatar, Badge, Icon, withBadge } from 'react-native-elements'
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const MessagesIcon = ({ tintColor }) => (
<Icon
type="MaterialCommunityIcons"
name="checkcircle"
size={24}
color={tintColor}
/>
);
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Home Page', headerShown: false }}
/>
<Stack.Screen
name="Search"
component={SearchScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Notifications"
component={NotificationsScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Map"
component={MapScreen}
changeoptions={{ headerShown: false }}
/>
<Stack.Screen
name="Settings"
component={SettingsScreen}
changeoptions={{ headerShown: false }}
/>
</Stack.Navigator>
);
}
function SettingsStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Settings"
component={SettingsScreen}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}
function App() {
function App() {
const [Acount, setAcount] = useState(0)
this.state = {
Acount: 2
};
handleacount = (data) => {
this.state = {
Acount: 9
};
alert(this.state.acount)
}
return (
<NavigationContainer>
<Tab.Navigator
tabBarOptions={{
activeTintColor: '#b08cf3',
inactiveTintColor: 'black',
}}>
<Tab.Screen
name="HomeStack"
component={HomeScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={30} />
),
}}
/>
<Tab.Screen
name="SearchStack"
component={SearchScreen}
options={{
tabBarLabel: 'Search',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons
name="account-search"
color={color}
size={30}
/>
),
}}
/>
<Tab.Screen
name="NotificationsStack"
component={NotificationsScreen}
options={{
tabBarBadge: 5,
tabBarLabel: 'Notifications',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="bell" color={color} size={30} />
),
}}
/>
<Tab.Screen
name="MapStack"
component={MapScreen}
options={{
tabBarLabel: 'Map',
tabBarIcon: ({ focused, color, size }) => {
return (
<View>
<MaterialCommunityIcons name="map-marker" size={30} color='rgb(68,68,68)' style={{ marginTop:0 }}/>
<View style={{position:'absolute', bottom:32, left:-38 }}>
<IconBadge
MainElement={
<View>
</View>
}
BadgeElement={
// here your text in badge icon
<Text style={{fontWeight: 900,fontFamily: "sans-serif-medium",
fontSize: 14,color:'#FFFFFF', Top:10 }}>{ this.state.acount }</Text>
}
IconBadgeStyle={
{width:20,
height:20,
borderWidth: 2,
borderColor: "#b5b5b5",
backgroundColor: '#ff8a8a'}
}
/></View>
</View>
);
},
}}
/>
<Tab.Screen
name="SettingsStack"
component={SettingsScreen}
options={{
tabBarLabel: 'Account',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons
name="account"
color={color}
size={30}
/>
),
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
export default App;
State belongs to the component so you should move it inside the App component like this
function App() {
const [account, setAccount] = useState(0)
...
}
But how do you call the setAccount from another page you wonder and there you need to have a look into React Context or Redux.
Context: https://reactjs.org/docs/context.html
Redux: https://redux.js.org/
I sorted it by place this in another page:
<Button
onPress={() => {increment(2)}} title="Click Me"
/>
Then in the function App I added
// State: a counter value
const [counter, setCounter] = useState(0)
increment = (data) => {
setCounter(data)
}
Not entirely sure how or why this works though?
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>
);
}
in the application I am creating I have set up bottom-tabs. They are functioning properly.
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator initialRouteName="Feed"
tabBarOptions={{activeTintColor: '#F78400'}}>
<Tab.Screen
name="Authentication" component={Authentication}
options={{
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return (
<Image
source={require("./assets/images/authentication.jpg")}
style={{ width: 20, height: 20 }}
/>
);
}
}}
/>
<Tab.Screen
name="Dashboard"
component={Dashboard}
options={{
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return (
<Image
source={require("./assets/images/dashboard.png")}
style={{ width: 20, height: 20 }}
/>
);
}
}}
/>
<Tab.Screen
name="Tools"
component={Tools}
options={{
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return (
<Image
source={require("./assets/images/tools.png")}
style={{ width: 20, height: 20 }}
/>
);
}
}}
/>
<Tab.Screen
name="Settings"
component={Settings}
options={{
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return (
<Image
source={require("./assets/images/settings.png")}
style={{ width: 20, height: 20 }}
/>
);
}
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
So now, I want to set up navigation to be able to go from one screen to another. I added the code of the stacks to the code of my tabs and when I want to go on antorher screen, I click a button to go on another screen, the name of the screen appear at the top of the page but it looks like it still the first screen. I don't get what's wrong
view config getter callback for component,
could you please explain to me how to do? Thanks a lot.
import React from 'react'
import { Image } from 'react-native'
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs'
import { createStackNavigator} from "#react-navigation/stack"
import { NavigationContainer } from '#react-navigation/native'
import Authentication from '../../Screens/Authentication'
import Login from '../../Screens/Authentication'
import Signup from '../../Screens/Authentication'
import Tools from '../../Screens/Tools'
import Dashboard from '../../Screens/Dashboard'
import Settings from '../../Screens/Settings'
import Scan from '../../Screens/Tools'
import i18n from '../../src/i18n'
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
function ScreenNavigator() {
return(
<Stack.Navigator>
<Stack.Screen name = 'Authentication' component = {Authentication}/>
<Stack.Screen name = 'Login' component = {Login}/>
<Stack.Screen name = 'Signup' component = {Signup}/>
<Stack.Screen name = 'Tools' component = {Tools}/>
<Stack.Screen name = 'Scan' component = {Scan}/>
<Stack.Screen name = 'Dashboard' component = {Dashboard}/>
<Stack.Screen name = 'Settings' component = {Settings}/>
</Stack.Navigator>
)
}
export default function AppNavigation() {
return (
<NavigationContainer>
<Tab.Navigator initialRouteName="Feed"
tabBarOptions={{activeTintColor: '#F78400'}}>
<Tab.Screen
name={i18n.t("app.auth")}
component={ScreenNavigator}
options={{
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return (
<Image
source={require("../../assets/images/authentication.jpg")}
style={{ width: 20, height: 20 }}
/>
);
}
}}
/>
<Tab.Screen
name={i18n.t("app.dash")}
component={Dashboard}
options={{
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return (
<Image
source={require("../../assets/images/dashboard.png")}
style={{ width: 20, height: 20 }}
/>
);
}
}}
/>
<Tab.Screen
name={i18n.t("app.tools")}
component={Tools}
options={{
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return (
<Image
source={require("../../assets/images/tools.png")}
style={{ width: 20, height: 20 }}
/>
);
}
}}
/>
<Tab.Screen
name={i18n.t("app.settings")}
component={Settings}
options={{
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return (
<Image
source={require("../../assets/images/settings.png")}
style={{ width: 20, height: 20 }}
/>
);
}
}}
/>
</Tab.Navigator>
</NavigationContainer>
)
}
You are not passing components when initializing the navigation
The below code
<Stack.Screen name = 'Authentication' component = 'Authentication'/>
You have passed a string for component which is causing the error, this should change to
<Stack.Screen name = 'Authentication' component = {Authentication}/>
You will have to change other screens in the stack as well
I am facing some problems with FontAwesome icons. (I have tried with MaterialCommunityIcons and normal Icons, but the same result)
They don't appear in the bottom Tab navigation, as also under Social networks. (The other icons are from react-native-settings-page)
Here is a screenshot:
Here is the TabNavigation:
import React from 'react';
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { MaterialCommunityIcons } from '#expo/vector-icons';
import HomeNavigator from '../navigation/HomeNavigator';
import NewsNavigator from '../navigation/NewsNavigator';
import settings from '../config/settings';
import i18n from "../locales/i18n";
const Tab = createBottomTabNavigator();
function TabNavigation(props) {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ color }) => {
let iconName;
if (route.name === 'Home') {
iconName = 'home';
}
else if (route.name === 'News') {
iconName = 'newspaper';
}
// You can return any component that you like here!
return <MaterialCommunityIcons color={color} icon={iconName} size={25} />;
},
})}
tabBarOptions={{
activeTintColor: settings.colors.activecolor,
inactiveTintColor: settings.colors.fontcolor,
activeBackgroundColor: settings.colors.navigation,
inactiveBackgroundColor:settings.colors.navigation,
}}
>
<Tab.Screen name="Home" options={{ tabBarLabel: i18n.t('navigation.home') }} component={HomeNavigator} />
<Tab.Screen name="News" options={{ tabBarLabel: i18n.t('navigation.news') }} component={NewsNavigator} />
</Tab.Navigator>
);
}
export default TabNavigation;
Here are my colors, but I think they are not making the problem:
export default {
colors: {
navigation: '#000',
bgcolor: "#000",
fontcolor: '#fff',
activecolor: '#dd163b',
settingsbackground: '#c3c3c3',
},
languages: {
}
}
You are using tabBarIcon as part of the navigator this should be passed to the screen level options like below
<Tab.Screen
name="Home"
options={{
tabBarLabel: i18n.t('navigation.home'),
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="home" color={color} size={20} />
),
}}
component={HomeNavigator}
/>
<Tab.Screen
name="News"
options={{
tabBarLabel: i18n.t('navigation.news'),
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="newspaper" color={color} size={20} />
),
}}
component={NewsNavigator}
/>
import React from 'react';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import {MaterialCommunityIcons,Feather} from '#expo/vector-icons';
import {VideoTab} from './VideoTab';
import {EbookTab} from './EbookTab';
import {TestTab} from './TestTab';
import {NotesTab} from './NotesTab';
const Bottom = createMaterialBottomTabNavigator();
export const BottomNav = ({navigation,route})=>{
return (
<Bottom.Navigator
initialRouteName="VideoTab"
activeColor="#1ca6d1"
inactiveColor="red"
labeled='true'
barStyle={{ backgroundColor: '#ffffff' }}
>
<Bottom.Screen
name="VideoTab"
component={VideoTab}
options={{
title:'Video',
tabBarLabel: 'Class',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="lightbulb-on-outline" color={color} size={26} />
),
}}
/>
<Bottom.Screen
name="NotesTab"
component={NotesTab}
options={{
title:'Notes',
tabBarLabel: 'Notes',
tabBarIcon: ({ color }) => (
<Feather name="book" color={color} size={26} />
),
}}
/>
<Bottom.Screen
name="EbookTab"
component={EbookTab}
options={{
tabBarBadge:true,
title:'Ebook',
tabBarLabel: 'QuestionBank',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="account" color={color} size={26} />
),
}}
/>
<Bottom.Screen
name="TestTab"
component={TestTab}
options={{
title:'Test',
tabBarLabel: 'Test',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="account" color={color} size={26} />
),
}}
/>
</Bottom.Navigator>
);
}
And this bottom navigation is inside a stack navigator.
Every screen name is a tab screen and every tab screen contain 3 tab.
When I am clicking any tab, then I want to change header title according to tab.
How to create this type of navigation header title in react native?
If you want to have every tab name to be the top try this: https://reactnavigation.org/docs/screen-options-resolution/
Check out the getHeaderTitle function and the switch statement below that - it helped me achieve this behavoir.