React native reload bottom tabs on each click for webview - react-native

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>
);
}
}

Related

React Native Drawer Navigation show headerLeft

I have a Drawer navigator which is inside a Stack navigator and I'd like to display a header. Currently I can display everything I want however because the header is defined at the Stack level the navigation inside the header is stack level not drawer level which is preventing me from opening the drawer.
Root stack
<Stack.Navigator
initialRouteName={"Splash"}
screenOptions={{}}
component={SplashScreen}
>
{ auth ?
<Stack.Screen name="Drawer" component={DrawerStack} options={({ navigation }) => ({
title: 'My App',
headerLeft: () => (
<HeaderLeft navigation={ navigation } />
),
headerRight: () => (
<HeaderRight navigation={ navigation } />
),
headerTitleAlign: 'center',
headerTintColor: 'white',
headerStyle: {
backgroundColor: '#5742f5'
},
})} />
:
<Stack.Screen name="Auth" component={AuthStack} options={{
headerShown: false
}}/>
}
</Stack.Navigator>
Drawer stack
<Drawer.Navigator options={{
headerShown: true,
headerLeft: () => (
<HeaderLeft navigation={ navigation } />
),
}}>
<Drawer.Screen
name="Conversations"
options={{
title: props.title,
}}
component={ChatListScreen}
/>
<Drawer.Screen
name="ChatRoom"
options={{
drawerLabel: () => null,
title: null,
drawerIcon: () => null
}}
component={ChatRoomScreen}
/>
</Drawer.Navigator>
Note in the drawer navigator the line with headerLeft does nothing and is there to show where I attempted to put it thinking it would work. I did think it might be overlaying the stack one so I commented out the stack one and it didn't work.
HeaderLeft
export default function HeaderLeft ({ navigation }) {
const openMenu = () => {
navigation.toggleDrawer();
}
return (
<View style={styles.header}>
<Icon name='menu' onPress={openMenu} size={28} style={styles.icon} color="white"/>
</View>
)
}
My question is how can I refactor this to enable me to have the HeaderLeft component work to open the drawer. I will be adding more screens so ideally something I don't have to pass to each screen but if that is what works I am good with it too.
Options in DrawerStack not work. I modified it:
<Drawer.Navigator
screenOptions={{
headerLeft: () => <HeaderLeft />,
}}>
// ...
</Drawer.Navigator>
And a little change in HeaderLeft:
import { useNavigation } from '#react-navigation/native';
function HeaderLeft() {
const navigation = useNavigation();
const openMenu = () => {
navigation.toggleDrawer();
};
// render your Button
}
Demo: https://snack.expo.dev/#pqv2210/0d613b

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

How to send props from createBottomTabNavigation to every tab screen?

I am using createBottomTabNavigation and I have 4 screens which I can access by pressing the tab bar screen in the bottom of my screen. I am also using Stack Navigation to display the title of the screen there and also all screens have the same settings icon.
I could make the same function in every screen that takes care of onPress event on the Settings icon but that is repetitive and I don't want to do it.
My question is - is there a way for me to pass a function as a props from the App component which holds the bottom navigation to every screen?
App screen code:
<NavigationContainer >
<Tab.Navigator initialRouteName="Home" tabBarOptions={{
activeTintColor: '#FF9F0A',
inactiveTintColor:'white',
style: {
backgroundColor:'#000000',//color you want to change
borderTopWidth: 0,
paddingTop:5,
paddingBottom:5,
},
}}>
<Tab.Screen name="Home" component={Home} options={{
tabBarLabel: 'HOME',
tabBarIcon: ({ color, size }) => (
<HomeTabIcon name="home" color={color} size={size} />
),
}}/>
<Tab.Screen name="Controls" component={Controls} options={{
tabBarLabel: 'CONTROLS',
tabBarIcon: ({ color, size }) => (
<ControlsTabIcon name="controls" color={color} size={size} />
),
}}/>
<Tab.Screen name="Charging" component={Charging} options={{
tabBarLabel: 'CHARGING',
tabBarIcon: ({ color, size }) => (
<ChargingTabIcon name="charging" color={color} size={size}/>
),
}}/>
Charging screen:
function Charging() {
return (
<View style={globalStyles.container}>
<Text>Charging</Text>
<StatusBar style="auto" />
</View>
);
}
export default function ChargingStackScreen() {
return (
<ChargingStack.Navigator>
<ChargingStack.Screen name="CHARGING" component={Charging} options={{
headerRight: () => (
<View style={globalStyles.headerRight}>
<SettingsIcon />
</View>
),
headerTitleAlign:'left',
headerTintColor: 'white',
headerTitleStyle: globalStyles.headerTitle,
headerStyle: globalStyles.header
}}/>
</ChargingStack.Navigator>
);
}
So what I think you should do is have the header as a separate component, where you can use the useNavigation hook (assuming you're using the latest version of react-navigation), and have the settings button do the navigation you need. Then just render the header component once above the Tab.Navigator instead of rendering it on every screen.
Something like:
function Header(props){
const navigation = useNavigation();
// component code
<SettingsButton onPress={() => navigation.navigate(whatever)}/>
}
And then I am pretty sure (not 100% though) that you can render it in your NavigationContainer, something like:
<NavigationContainer >
<Header/>
<Tab.Navigator initialRouteName="Home" tabBarOptions={{
// rest of the code

React Navigation 5 Passing params to tabNavigation / Tab Navigator

Hi is that possible to pass certain parameter when pressing the TabBar?
Currently I have an administrator who could view lists of data in ProfileScreenPrimary, and then when he click the list he will go to profilescreen secondary that show details of the data from parameter
it works fine
and then i made a route for customer that will skip the profilescreenprimary and will go to profilescreensecondary. but it got error which is the route.params is undefined, is there any way to pass the parameter / replace the parameters with context that i provide?
, i have tabBar like this
function BottomTabNavigator() {
return (
<Tab.Navigator>
<Tab.Screen
name="Profile"
component={ProfileStackScreen}
options={{
tabBarLabel: 'PROFILE',
tabBarIcon: ({color, size}) => (
<Icon name="git-branch" color={color} size={25} />
),
}}
/>
<another tab....>
</Tab.Navigator>
);
}
this is my profileStackScreen
function ProfileStackScreen({navigation, route}) {
const {myContext}=useContext(MYCONTEXT)
return (
{
myContext.role = 'admin' && (
<Stack.Screen
name="ProfileScreenPrimary"
component={ProfileScreenPrimary}
options={({route}) => ({
title: 'List'
headerTitleStyle: headerTitleStyle,
})}
/>
)
}
<Stack.Screen
name="ProfileScreenSecondary"
component={ProfileScreenSecondary}
options={({route}) => ({
title: `${!route.params.ProfileName ? myContext.profileName : route.params.ProfileName}`, -> this return route.params.ProfileName is undefined
headerTitleStyle: headerTitleStyle,
})}
/>
<otherstack>
)

Reset StackNavigator inside createBottomTabNavigator on tabBarOnPress

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>