Drawer opens and immediately closes after keyboard dismiss - reactjs

I faced a strange problem that happened only on a small screen, I tested on 480x800 4 inches and 2400x1080 6.6inches screen, and that happened on the smaller one (480x800), the drawer flashes on any window that contains a text input after the keyboard closes.
Just for understanding better the problem there's a video
#react-navigation/drawer#6.1.8
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItem,
} from '#react-navigation/drawer'
const Drawer = createDrawerNavigator()
<Drawer.Navigator
detachInactiveScreens={false}
useLegacyImplementation={false}
initialRouteName="Home"
drawerContent={(props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItem
icon={() => {
return (
<Ionicons
light
name="arrow-back-outline"
size={20}
color="black"
/>
)
}}
label="Menu"
onPress={() =>
props.navigation.dispatch(DrawerActions.closeDrawer())
}
/>
<View
style={{
borderBottomColor: '#999999',
borderBottomWidth: 0.5,
}}
/>
</DrawerContentScrollView>
)
}}
screenOptions={() => {
return {
swipeEnabled: true,
headerShown: false,
}
}}
>
<Drawer.Screen name="Home" component={Home} />
</Drawer.Navigator>

Related

goBack not working in nested navigators react native. TabNavigator and StackNavigator

I have this problem several days ago and I can't find a solution.
This is my navigation structure
Index.tsx -->
<NavigationContainer>
<Stack.Navigator initialRouteName='tabsBottomHome'
screenOptions={{
headerTitle: () => <Header />,
headerBackground: () => <HeaderBackground />,
headerLeft: ({ onPress, canGoBack }) =>
canGoBack ? (
<Pressable onPress={onPress} style={{ width: 30, height: 15 }}>
<ArrowLeft height={15} width={15} style={{ marginLeft: 15 }} />
</Pressable>
) : (
<Pressable style={{ width: 65, height: 35 }}></Pressable>
),
headerRight: () => <HeaderRight />,
}}
>
{state.isSignIn ? (
<>
<Stack.Screen
name='tabsBottomHome'
component={TabsBottomHome}
options={{headerShown: false }}
/>
</>
) : (
<>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="LoginError"
component={LoginError}
/>
</>
)}
</Stack.Navigator>
</NavigationContainer>
This would be the first navigation of my application. So far everything is going well.
TabsBottomNavigation -->
<Tab.Navigator
initialRouteName='Home'
screenOptions={{
headerShown:true,
tabBarShowLabel:false,
tabBarStyle:style.tabsBottomContainer,
unmountOnBlur: true,
headerTitle: () => <Header />,
headerBackground: () => <HeaderBackground />,
headerLeft: () =>
routeName != "Home" ? (
<Pressable onPress={navigateBack} style={{ width: 65, height: 15 }}>
<ArrowLeft height={15} width={15} style={{ marginLeft: 15 }} />
</Pressable>
)
: (
<Pressable style={{ width: 65, height: 35 }}></Pressable>
)
,
headerRight: () => <HeaderRight />,
}}
sceneContainerStyle={style.backgroundContent}
screenListeners={({route})=>({
state: ()=> {
setRouteName(route.name);
}
})}
backBehavior={'history'}
>
<Tab.Screen
name='Assets'
component={AssetScreen}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconAsset}
style={{
tintColor: focused ? '#00B2DF' : '',
marginTop: 8
}}
/>
</View>
)}} />
<Tab.Screen
name='GatewayStack'
component={ConnectGatewayStack}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconBluetooth}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)}} />
<Tab.Screen
name='Home'
component={HomeScreen}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconHome}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)
}} />
</Tab.Navigator>
everything is fine here too, the conflict is in the ConnectGatewayStack stack
ConnectGatewayStack -->
export type StackConnectList = {
Connect: undefined;
QRScan: undefined;
GatewayList: undefined;
GatewayInfo: undefined;
NotFoundGateway: undefined;
GatewayDetected: undefined;
ErrorConnecting: undefined;
}
const GatewayStack = createStackNavigator<StackConnectList>();
const ConnectGatewayStack = () =>{
return (
<GatewayStack.Navigator initialRouteName='Connect'
screenOptions={{headerShown:false}}
>
<GatewayStack.Screen name='Connect' component={ConnectScreen} />
<GatewayStack.Screen name='GatewayList' component={GatewayList} />
<GatewayStack.Screen name='GatewayInfo' component={GatewayInfo} />
<GatewayStack.Screen name='QRScan' component={QRScanScreen} />
<GatewayStack.Screen name='NotFoundGateway' component={NotFoundGateway} />
<GatewayStack.Screen name='GatewayDetected' component={GatewayDetected} />
<GatewayStack.Screen name='ErrorConnecting' component={ErrorConnecting} />
</GatewayStack.Navigator>
)
}
export {ConnectGatewayStack};
When I navigate to the ConnectGatewayStack tab, which contains the other components that I just showed, if I go to a child component and press the back button in header, it returns directly to the TabsBottomHome (that is, to the Tabs navigation) and not to the component that was previously visited.
For the navigation back, i use
import { useNavigation } from '#react-navigation/core';
whit
const navigation = useNavigation();
navigation.goback();
I tried whit diferents methods, but none solved my problem.
example test whit
backBehavior={'history'}
backBehavior={'order'}
and many functions of the core react-native and react-native-navigation
any ideas?
sorry for my bad english and thank you very much

Payload not handled by any navigator in react navigation 6

I am updating my react-native app to use react navigation 6 and I'm trying to figure out how to connect to a screen.
The screen I'm trying to link/navigate to uses a bottomtabnavigator, and looks like this:
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
export const PatientScreen = () => {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator screenOptions={{ headerShown: false }} initialRouteName={'Visits'}>
<Tab.Screen name="Visits" component={VisitsTab}
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => (
<FontAwesome name="street-view" color={color} size={size} />
),
}}
/>
<Tab.Screen name="Chart" component={ChartTab}
options={{
tabBarLabel: 'Charts',
tabBarIcon: ({ color, size }) => (
<FontAwesome name="id-badge" color={color} size={size} />
),
}}
/>
<Tab.Screen name="Goals" component={GoalsTab}
options={{
tabBarLabel: 'Edit Goals',
tabBarIcon: ({ color, size }) => (
<FontAwesome name="trophy" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
}
I am trying to link to the above from within a screen that is part of a different navigator. That screen looks like this:
import { StyleSheet, Text, View, Tab, Button } from 'react-native';
import { PatientScreen } from './PatientScreen';
export const CaseloadScreen = ({navigation}) => {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Caseload</Text>
<Button title="Patient"
onPress={() => navigation.navigate('PatientScreen', { screen: 'Visits' })}
/>
</View>
);
}
When I click on the button above, I get this error:
The action 'NAVIGATE' with payload undefined was not handled by any navigator.
Do you have a screen named 'PatientScreen'?
So clearly I'm missing something, but it's unclear to me what that is. How do I make this PatientScreen which uses a bottomTabNavigator, linkable from the button link I listed above?
My navigator for the Caseload screen looks like this:
import React from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '#react-navigation/drawer';
import { LoginScreen } from '../screens/LoginScreen';
import { CaseloadScreen } from '../screens/CaseloadScreen';
import { WeeklyScreen } from '../screens/WeeklyScreen';
import { ProfileScreen } from '../screens/ProfileScreen';
import { Ionicons, FontAwesome, MaterialCommunityIcons, AntDesign } from '#expo/vector-icons';
import { AvailablePatientScreen } from '../screens/AvailablePatientScreen';
const CustomDrawerContent = (props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} style={{
activeTintColor: {
color: '#fff',
},
}} />
</DrawerContentScrollView>
);
}
const Drawer = createDrawerNavigator();
const DrawerNavigation = () => {
const icons = {
tintColor: '#fff',
size: 20,
}
return (
<Drawer.Navigator initialRouteName={'Caseload'}n
drawerContent={(props) => <CustomDrawerContent {...props} />}
screenOptions={{
labelStyle: {
color: '#fff',
},
inactiveTintColor: {
color: '#fff',
},
drawerStyle: {
backgroundColor: 'rgb(61,77,138)',
width: 240,
activeTintColor: 'rgb(61,77,138)',
activeBackgroundColor: '#fff',
inactiveTintColor: '#fff',
inactiveBackgroundColor: 'rgb(61,77,138)',
},
}}
>
<Drawer.Screen name="Caseload" component={CaseloadScreen} options={{
drawerIcon: () => (<Ionicons name="ios-home" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="Weekly Summary" component={WeeklyScreen} options={{
drawerIcon: () => (<FontAwesome name="bar-chart" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="Available RiverKids" component={AvailablePatientScreen} options={{
drawerIcon: () => (<FontAwesome name="child" size={icons.size} color={icons.tintColor} />)
}} />
<Drawer.Screen name="My Profile" component={ProfileScreen} options={{
drawerIcon: () => (<AntDesign name="profile" size={icons.size} color={icons.tintColor} />)
}} />
{/* <Drawer.Screen name="Patient" component={PatientScreen} options={{
drawerIcon: () => (<FontAwesome name="bar-chart" size={icons.size} color={icons.tintColor} />)
}} /> */}
<Drawer.Screen name="Login" component={LoginScreen} options={{ title: 'Sign Out',
drawerIcon: () => (<MaterialCommunityIcons name="logout" size={icons.size} color={icons.tintColor} />)
}} />
</Drawer.Navigator>
);
}
export const Navigator = () => {
return (
<NavigationContainer>
<DrawerNavigation />
</NavigationContainer>
);
}
In your drawer navigator there is no screen defined with the name 'PatientScreen';
I can see a commented screen in your drawer navigator which has a name Patient and the component is PatientScreen. If you wish to navigate the Patient Screen from the drawer, do uncomment that code and then do the below
import { StyleSheet, Text, View, Tab, Button } from 'react-native';
export const CaseloadScreen = ({navigation}) => {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Caseload</Text>
<Button title="Patient"
onPress={() => navigation.navigate('Patient', { screen: 'Visits' })}
/>
</View>
);
}
Or else if you wish to navigate the PatientScreen only from the Caseload Screen, then create a Stack Navigator with the caseload and patient screen and then in the drawer navigator use that stack navigator in place of caseload screen

is there any method to re-render the screen to bottom tab nav v5 in react-native

Hy, I'm using react-native bottom tabs navigation the first time I'm having an issue to re-render the screen when I get back to some other tab. I try to use isFocused in useEffect() but it didn't work for me.
const LandScreen = ({navigation}) => {
return (
<Tab.Navigator
tabBarOptions={{
showLabel: false,
activeTintColor: colors.primary,
inactiveTintColor: colors.textHead,
}}
>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{
tabBarIcon: ({focused, color, size}) => {
const icon = focused ? 'home' : 'home';
return <Icon name={icon} color={color} size={size} />;
},
}}
/>
<Tab.Screen
name="Message"
component={ChatStackScreen}
options={{
tabBarIcon: ({focused, color, size}) => {
const icon = focused ? 'chatbox-ellipses' : 'chatbox-ellipses';
return <Icon name={icon} color={color} size={size} />;
},
}}
/>
<Tab.Screen
name="Requests"
component={RequestStackScreen}
options={{
tabBarIcon: ({focused, color, size}) => {
const icon = focused ? 'heart' : 'heart';
return <Icon name={icon} color={color} size={size} />;
},
}}
/>
<Tab.Screen
name="Notifications"
component={NotificationStackScreen}
options={{
tabBarIcon: ({focused, color, size}) => {
const icon = focused ? 'notifications' : 'notifications';
return <Icon name={icon} color={color} size={size} />;
},
}}
/>
<Tab.Screen
name="Profile"
component={ProfileScreenScreen}
options={{
tabBarIcon: ({focused, color, size}) => {
const icon = focused ? 'person' : 'person';
return <Icon name={icon} color={color} size={size} />;
},
}}
/>
</Tab.Navigator>
);
};
Each Tab component having a stack inside of it.
Someone informs me how to rerender the bottom navigation tabs?
If I understand you correctly, you want the screen to re-render when you click on a bottom tab navigation button.
This can be accomplished by either adding the 'focus' event listener via the react navigation docs https://reactnavigation.org/docs/function-after-focusing-screen/
Or by explicitly calling 'navigation.navigate' when a bottom tab is pressed.
Assuming I understand your question, all you want to do is re-render the icons when the tab changes?
React Navigation has docs & an example for this use-case for tab-based navigation here.
Posting the code sample from the docs here for ease-of-access:
import Ionicons from 'react-native-vector-icons/Ionicons';
// (...)
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? 'ios-information-circle'
: 'ios-information-circle-outline';
} else if (route.name === 'Settings') {
iconName = focused ? 'ios-list-box' : 'ios-list';
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
If your question meant re-rendering the screen when the tab changes:
Leveraging useEffect with useIsFocused should work when changing tabs. You haven't included your example with those hooks, so I'm not exactly sure how you're using it.
The following snippet should get you up and running with said hooks. In this case, you can run whatever you want inside the useEffect when switching tabs, where the active tab gets triggered.
If for some reason you just want the UI to get updated/persisted based on some data between tab changes you might want to consider using Redux.
import React, { useEffect } from "react";
import { Text, View } from "react-native";
import { NavigationContainer } from "#react-navigation/native";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { useIsFocused } from "#react-navigation/core";
function HomeScreen() {
const isFocused = useIsFocused();
useEffect(() => {
if (isFocused) {
console.log("HELLO HOME");
}
}, [isFocused]);
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Home!</Text>
</View>
);
}
function SettingsScreen() {
const isFocused = useIsFocused();
useEffect(() => {
if (isFocused) {
console.log("HELLO SETTINGS");
}
}, [isFocused]);
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}

How to add multiple divider component in a react navigation drawer

I have a drawer navigation, what I wanted to happen is add divider separating the drawer icon and texts, but I get an error instead
Error is: A navigator can only contain screen components...
Here is my approach:
function DrawerNav(): React$Element<{}> {
return (
<Drawer.Navigator
drawerStyle={styles.drawerStyle}
drawerContentOptions={{
activeTintColor: 'white',
inactiveTintColor: 'white',
activeBackgroundColor: '#163E69',
inactiveBackgroundColor: '#02152B'
}}>
<Drawer.Screen
name="Dashboard"
component={Dashboard}
options={{
drawerIcon: () => (
<Image source = {"assets/icons/dashboard.png"} />
),
}}
/>
<DrawerDivider label="Account" /> // This is my divider component
<Drawer.Screen
name="Profile"
component={Profile}
options={{
drawerIcon: () => (
<Image source={'assets/icons/profile.png'} />
),
}}
/>
<DrawerDivider label="Actions" /> // also my divider component
<Drawer.Screen
name="Settings"
component={Settings}
options={{
drawerIcon: () => (
<Image source={'assets/icons/settings.png'} />
),
}}
/>
<DrawerDivider label="Actions" /> // also my divider component
<Drawer.Screen
name="Logout"
component={Logout}
options={{
drawerIcon: () => (
<Image source={'assets/icons/logout.png'} />
),
}}
/>
</Drawer.Navigator>
);
}
Any suggestions/help are appreciated.
this how I implemented it in my project , you need to create a custom drawerContent component , drawerContent gives incredible amount of flexibility you can literally create what ever you want with it .
Navigator :
import DrawerContent from './DrawerContent'
import { createDrawerNavigator } from '#react-navigation/drawer';
const Navigator =({authenticated,userType})=>{
const Drawer = createDrawerNavigator();
return <Drawer.Navigator
screenOptions={{headerShown:false}}
initialRouteName="INTIALROUTE"
drawerContent={props => <DrawerContent {...props} />}
>
<Drawer.Screen name="route1" component={Screen1} />
<Drawer.Screen name="route1" component={Screen2} />
</Drawer.Navigator>
}
the custom drawerContent component :
import React from 'react'
import {StyleSheet,View,Text,TouchableOpacity} from 'react-native'
import {DrawerContentScrollView,DrawerItem} from '#react-navigation/drawer';
const DrawerContent=(props)=> {
const {navigation}=props
const naviagetToRoute=(e)=>{
navigation.navigate(route)
}
//here you can return diffrent drawerContent based on auth state for example
if(isAuthenticated){
//isAuthenticated can be passed through props using redux's connect or context api
return <View style={{flex:1}}>
<DrawerContentScrollView {...props}>
<TouchableOpacity onPress={naviagetToRoute}>
<View style={styles.drawerItem}>
<Image source = {"assets/icons/logout.png"} />
<Text style={{color:colors.BLACK}} >Logout</Text>
</View>
</TouchableOpacity>
</DrawerContentScrollView>
</View>
}
return (
<View style={{flex:1}}>
<DrawerContentScrollView {...props}>
<TouchableOpacity onPress={naviagetToRoute}>
<View style={styles.drawerItem}>
<Image source = {"assets/icons/dashboard.png"} />
<Text style={{color:colors.BLACK}} >DashBoard</Text>
</View>
</TouchableOpacity>
</DrawerContentScrollView>
</View>
)
}
export default DrawerContent
const styles = StyleSheet.create({
drawerItem: {
display :'flex',
flexDirection:'row',
alignItems:'center',
justifyContent:"space-between",
padding:16,
elevation:12,
backgroundColor:'#fff',
borderRadius:12,
marginBottom:16,
flex:1
}
});

How to provide a custom style to React navigation drawer screen title

I'm using React Navigation drawer and i want to have a different fontSize (custom styling) for each drawer screen title. Changing the labelStyle in the drawerContentOptions would change the fontSize for all the drawer screen titles and I wanna have each one customized.
<Drawer.Navigator
drawerStyle={{
backgroundColor: Colors.mainBackground,
width: WIDTH * 0.6,
}}
drawerContentOptions={{
activeTintColor: Colors.mainForeGround,
itemStyle: { marginVertical: 8, marginHorizontal: 8 },
labelStyle: {
fontSize: 18,
},
}}
>
<Drawer.Screen name="Profile" component={Profile}
options={{
title: 'Profile Name',
drawerIcon: ({ color }) => {
return <Icon name={'account'} size={ICON_SIZE} color={color} />
},
}}
/>
<Drawer.Screen name="Menu" component={Menu}
options={{
title: 'Shopping menu',
drawerIcon: ({ color }) => {
return <Icon name={'menu'} size={ICON_SIZE} color={color} />
},
}}
/>
<Drawer.Screen name="Cart" component={Cart}
options={{
title: 'Shopping cart',
drawerIcon: ({ color }) => {
return <Icon name={'cart'} size={ICON_SIZE} color={color} />
},
}}
/>
<Drawer.Screen name="Settings" component={Settings}
options={{
title: 'Settings',
drawerIcon: ({ color }) => {
return <Icon2 name={'settings'} size={ICON_SIZE} color={color} />
},
}}
/>
</Drawer.Navigator>
Drawer.Navigator provides a prop called drawContent which needs to return a React component which will be used to render the contents of the drawer.
Usage:
function CustomDrawerContent(props) {
return (
<Here goes your code for rendering individual elements of your drawer>
);
}
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Feed" component={Feed} />
<Drawer.Screen name="Article" component={Article} />
</Drawer.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyDrawer />
</NavigationContainer>
);
}
For full example, refer link

Resources