I have created a DrawerNavigator in my react native app which looks like this.
I just dont like the default header that react- native gives. So I wanna access it through an icon. I guess also using the onPress condition
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
// importing of all screens
const Drawer = createDrawerNavigator();
const DrawerContent = () => {
return (
<Drawer.Navigator>
<Drawer.Screen
name="Home"
component={CategoryStack}
/>
<Drawer.Screen name="Aboutus" component={Aboutus} />
<Drawer.Screen name="Interest Recieved" component={InterestRecieved} />
</Drawer.Navigator>
);
};
const Stack = createStackNavigator();
const MainStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Loading"
component={Loading}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
};
export default MainStack;
How do I open it using an onPress of an icon?
Thanks!
React navigation useNavigation hook expose drawer actions - toggleDrawer,openDrawer and closeDrawer event handlers which you can use to open or close drawer.
import React from "react";
import { View, Text, StyleSheet, Pressable } from "react-native";
import { useNavigation } from "#react-navigation/native";
const ToggleDrawer = () => {
const { toggleDrawer,closeDrawer,openDrawer } = useNavigation();
return (
<Pressable onPress={toggleDrawer}>{/** Add your Icon Here */}</Pressable>
);
};
You can check in-depth drawer example
In the header options you can customize the header and add for example an icon on the top left side like this.
useLayoutEffect(() => {
navigation.setOptions({
title: 'ScreenName',
headerLeft: () => (
<View style={{ marginLeft: 15 }}>
<TouchableOpacity onPress={() => navigation.openDrawer()} >
{*INSERT ICON HERE*}
</TouchableOpacity>
</View>
),
})
})
Related
I'm using react-native-toast-notifications package for showing in-app notifications.
I'm trying to integrate it for showing notifications when a chat arrives. But this notification is also being displayed on the chat room screen where the one-to-one chat happens.
How can I prevent the notification being appeared on the chat room screen?
This is my provider component
<ToastProvider
swipeEnabled={true}
placement="top"
duration={5000}
animationType="zoom-in"
animationDuration={300}
renderType={{
message_toast: (toast) => <ToastContainer toast={toast} />,
}}
>
<SymbolsProvider>
<Navigation />
</SymbolsProvider>
</ToastProvider>
I'm using the useToast() hook provided by the package to show notifications
const toast = useToast();
toast.show(socketMessage.username + " Sent a message", {
position: "bottom",
duration: 3000,
style: toastStyle,
type: "success",
});
Sent a message
This notification is appearing on the chat room screen also which should not be happening.
Here's an example base on the comment under the question:
import { ToastProvider } from 'react-native-toast-notifications'
import {NavigationContainer} from '#react-navigation/native'
import Screens from './screens/index'
export default function App() {
return (
<ToastProvider>
<NavigationContainer>
<Screens />
</NavigationContainer>
</ToastProvider>
);
}
import React from 'react';
import {
SafeAreaView,
View,
StyleSheet,
TouchableOpacity,
Text,
} from 'react-native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { useNavigation } from '#react-navigation/native';
import { useToast } from 'react-native-toast-notifications';
const Stack = createNativeStackNavigator();
const Drawer = createDrawerNavigator();
const ToastButton = ({ style}) => {
const toast = useToast();
const navigation = useNavigation();
const navState = navigation.getState();
console.log(navState.routeNames);
const currentRoute = navState.routeNames[navState.index];
const onPress = () => {
if (currentRoute != 'Chat') toast.show('Toast from ' + currentRoute);
};
return (
<TouchableOpacity style={[styles.container, style]} onPress={onPress}>
<Text>Show Toast</Text>
</TouchableOpacity>
);
};
const HomeScreen = (props) => {
return (
<View style={styles.flex}>
<ToastButton />
</View>
);
};
const ChatScreen = (props) => {
return (
<View style={styles.flex}>
<ToastButton />
</View>
);
};
export default function ScreenIndex(props) {
return (
<SafeAreaView style={{ flex: 1 }}>
<Drawer.Navigator useLegacyImplementation={true}>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Chat" component={ChatScreen} />
</Drawer.Navigator>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
flex: {
flex: 1,
backgroundColor: '#eef',
},
});
I have a main navigator in app.js
import React from 'react';
import LoginScreen from './src/screens/LoginScreen';
import HomeScreen from './src/screens/HomeScreen';
import { Image } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { Constans } from './src/constants/Constant';
import SignupScreen from './src/screens/SignupScreen';
import { EventScreen } from './src/screens/EventScreen';
const navigator = createStackNavigator(
{
Login: {
screen: LoginScreen,
navigationOptions: {
headerShown: false
}
},
SignUp: {
screen: SignupScreen,
navigationOptions: {
headerShown: false
}
},
Home: {
screen: HomeScreen,
navigationOptions: {
headerLeft:()=>false,
headerTitle:()=> (
<Image style={{width:35,height:35}} source={Constans.logoImage}/>
)
}
},
Event:{
screen:EventScreen,
navigationOptions: {
headerLeft:()=>false,
headerTitle:()=> (
<Image style={{width:35,height:35}} source={Constans.logoImage}/>
)
}
}
},
{
initialRouteName: 'Home'
}
);
const AppContainer = createAppContainer(navigator);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
and when I go HomeScreen I have also menu navigator.
import React from 'react';
import Icon from 'react-native-vector-icons/FontAwesome';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { TabEventsScreen } from './TabEventsScreen';
import { TabForYouScreen } from './TabForYouScreen';
import { TabProfileScreen } from './TabProfileScreen';
const Tab = createBottomTabNavigator();
export default function HomeScreen() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions=
{
({ route }) =>
(
{
tabBarIcon: ({ focused, color }) =>
{
return <Icon
name={route.name === 'Explore' ? "globe" : route.name === 'Profile' ? 'user' : route.name === 'Wallet' ? 'money' :'star'}
size={focused ? 32: 24}
color={color} />;
}
}
)
}
tabBarOptions=
{
{
activeTintColor: '#1F7A8C',
inactiveTintColor: 'gray',
}
}>
<Tab.Screen name="Explore" component={TabEventsScreen} />
<Tab.Screen name="For You" component={TabForYouScreen} />
<Tab.Screen name="Wallet" component={TabProfileScreen} />
<Tab.Screen name="Profile" component={TabProfileScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
in one tab screen I am trying to navigate Event screen of main navigator. How can I do it?
import React, { useState, useEffect } from 'react';
import { Constans } from './../constants/Constant';
import { View, ImageBackground, Text, ScrollView } from 'react-native';
import { TabEventsScreenStyle } from './../styles/TabEventsScreenStyle';
import { IncomingEvents } from './../services/TabEventsService';
import { EventCard } from './../components/Eventcard'
export function TabEventsScreen({navigation}) {
const [events, setEvents] = useState([]);
const [page, setPage] = useState(1);
_getEvents = () => {
return IncomingEvents(1, page, 20);
}
useEffect(() => {
setEvents(_getEvents().Events);
});
_OnButtonPress=(key)=>{
console.log(navigation)
navigation.navigate('Event',{itemId:key});
}
return (
<ScrollView>
<ImageBackground source={Constans.homeBackGroundImage} style={TabEventsScreenStyle.backgroundImage} >
<Text style={TabEventsScreenStyle.title}>Incoming Events</Text>
<View>
{
events.map(el =>
<Text style={TabEventsScreenStyle.text} onPress={()=> this._OnButtonPress(el.key)}>
<EventCard key={el.key} data={el}></EventCard>
</Text>
)
}
</View>
</ImageBackground>
</ScrollView>
);
}
my error is
The action 'NAVIGATE' with payload
{"name":"Event","params":{"itemId":1}} was not handled by any
navigator.
Do you have a screen named 'Event'?
If you're trying to navigate to a screen in a nested navigator, see
https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
I also tried
const parent_nav=navigation.dangerouslyGetParent();
console.log(navigation);
parent_nav.navigate('Event',{itemId:key});
but parent_nav is undefined
Thanks in advance
You can navigate as if all screens were at the same level.
Navigation actions are handled by current navigator and bubble up if couldn't be handled
For example, if you're calling navigation.goBack() in a nested screen, it'll only go back in the parent navigator if you're already on the first screen of the navigator. Other actions such as navigate work similarly, i.e. navigation will happen in the nested navigator and if the nested navigator couldn't handle it, then the parent navigator will try to handle it. In the above example, when calling navigate('Messages'), inside Feed screen, the nested tab navigator will handle it, but if you call navigate('Settings'), the parent stack navigator will handle it.
The source.
When you navigate, it will try to find your screen in the current navigation and if it failed, then will try with the parent until the root navigation.
Wrap your AppContainer with NavigationContainer instead of the TabNavigator, so that both the StackNavigator and TabNavigator use the same navigation prop
export default class App extends React.Component {
render() {
return(
<NavigationContainer>
<AppContainer />
<NavigationContainer/>
)}
}
And remove NavigationContainer from the TabNavigator
Here is how I nested Stack and Tab Navigator
import React from 'react';
import {Dimensions, StatusBar, StyleSheet} from 'react-native';
import {createMaterialBottomTabNavigator} from '#react-navigation/material-bottom-tabs';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import AScreen from './AScreen';
import BScreen from './BScreen';
import CScreen from './CScreen';
import DScreen from './DScreen';
import A from './a';
import B from './B';
import C from './C';
import D from './D';
const Tab = createMaterialBottomTabNavigator();
const Stack = createStackNavigator();
const BottomTab = () => {
return (
<Tab.Navigator
activeColor="#ff6362"
backBehavior="initialRoute"
barStyle={{backgroundColor: '#000000'}}>
<Tab.Screen
name="A"
component={AScreen}
options={{
tabBarLabel: 'A',
tabBarIcon: ({color}) => (
<MaterialCommunityIcons name="book-open" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="B"
component={BScreen}
options={{
tabBarLabel: 'B',
tabBarIcon: ({color}) => (
<MaterialIcons name="people" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="C"
component={CScreen}
options={{
tabBarLabel: 'C',
tabBarIcon: ({color}) => (
<MaterialIcons name="people" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="D"
component={DScreen}
options={{
tabBarLabel: 'D',
tabBarIcon: ({color}) => (
<MaterialIcons name="person-pin" color={color} size={26} />
),
}}
/>
</Tab.Navigator>
);
};
export default function AdminScreen(props) {
return (
<NavigationContainer>
<StatusBar hidden />
<Stack.Navigator headerMode="none">
<Stack.Screen name="BottomTab" component={BottomTab} />
<Stack.Screen name="A" component={A} />
<Stack.Screen name="B" component={B} />
<Stack.Screen name="C" component={C} />
<Stack.Screen name="D" component={D} />
</Stack.Navigator>
</NavigationContainer>
);
}
i am new in react native. i am create new basic app with navigation bar.
i have two screen.
Home
List
i want to change both navigation bar title With "Home Screen" and "List Screen"
i have one button in home Screen. when i tap on button it navigate to list screen.
my problem is i can't change the title in list screen.
App.js
import { createAppContainer } from '#react-navigation/native';
import { createStackNavigator } from 'react-navigation-stack';
import HomeScreen from './src/screens/HomeScreen';
import ListScreen from './src/screens/ListScreen';
const navigator = createStackNavigator({
Home: HomeScreen,
List: ListScreen
},{
initialRouteName: 'Home',
defaultNavigationOptions:{
title: 'Home Screen'
}
}
);
export default createAppContainer(navigator);
HomeScreen.js
import React from 'react';
import { View, Text, StyleSheet, Button, TouchableOpacity, Stack} from 'react-native';
const HomeScreen = props => {
return(
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
onPress={() => props.navigation.navigate('List')}
>
<Text>START</Text>
</TouchableOpacity>
</View>
);
};
ListScreen.js
import React from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
const ListScreen = () => {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>List Screen</Text>
</View>
);
};
const styles = StyleSheet.create({
});
export default ListScreen;
i am use expo-cli.
please help me.
If we put defaultNavigationOptions in createStackNavigator then it might not be possible to update the screen header component so to update the header for screens separately then we have to specify individual navigationOptions.
we can create a stack navigator, try the below way to manage headers dynamically.
const HomeNavigator = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: {
headerShown: true,
headerTitle: "Home"
}
}
})
we also can manage the header from screens as below another method:
const LoginScreen = props => {
return <View />
}
LoginScreen.navigationOptions = navData => {
return {
headerTitle: "Login",
headerTransparent: true,
headerShown: false
}
}
I assume you are using React Navigation v5, you may always refer to their code sample here.
If you are lazy to read their sample, their code snippet is as below
function StackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'My home' }}
/>
</Stack.Navigator>
);
}
Below is a sample code from me, which you can use..
StackNavigator.js - (You can name whatever you want)
import * as React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import ScreenA from '../Containers/ScreenA';
import ScreenB from '../Containers/ScreenB';
const Stack = createStackNavigator();
const AppFlow = () => {
return (
<NavigationContainer>
<Stack.Navigator name="Test App">
<Stack.Screen
name="First"
component={ScreenA}
options={{headerShown: true, title: 'Screen A Title'}}
/>
<Stack.Screen
name="Second"
component={ScreenB}
options={{headerShown: true, title: 'Screen B Title'}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
const MainStackNavigator = () => {
return AppFlow();
};
export default MainStackNavigator;
First.JS - (You can name whatever you want) Then at this "First" screen, you may navigate to "Second" screen by the following code
<TouchableOpacity
style={styles.button}
onPress={() => props.navigation.navigate('Second')}
>
<Text>START</Text>
</TouchableOpacity>
this url: https://streamable.com/no6anz, is a video showcasing my app's navigation, I want the ability to navigate from a Drawer screen to a SPECIFIC Tab Screen in my Tab Navigation.
For example: If i pressed let's say the 'Messages' drawer item, i would like to navigate to the My Account tab screen in the tab navigator.
So far my implementation has not been the best:
import React, {Fragment, Component} from 'react';
import {View, StyleSheet} from 'react-native';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import {createDrawerNavigator} from '#react-navigation/drawer';
import {createStackNavigator} from '#react-navigation/stack';
import Home from '../Views/HomeView';
import Cart from '../Views/CartView';
import MyAccount from '../Views/MyAccountView';
import Sidebar from '../Views/Sidebar';
import HomeIconColor from './CustomSVGIcons/HomeIconColor';
import CartIconColor from './CustomSVGIcons/CartIconColor';
import PersonIconColor from './CustomSVGIcons/PersonIconColor';
import MenuIconColor from './CustomSVGIcons/MenuIconColor';
import Contact from '../Views/screens/Contact';
import Messages from '../Views/screens/Messages';
import {
NavigationContainer,
DrawerActions,
useNavigation,
} from '#react-navigation/native';
import {BottomTabBar} from '#react-navigation/bottom-tabs';
import Login from '../Views/screens/Login';
import {create} from 'react-test-renderer';
import {createSwitchNavigator} from '#react-navigation/compat';
const Tab = createBottomTabNavigator();
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
const Switch = createSwitchNavigator();
class Navigator extends Component {
constructor() {
super();
this.state = {};
}
render() {
return (
<NavigationContainer>
<MyDrawerNavigation />
</NavigationContainer>
);
}
}
const MyTabs = (props) => {
const navigation = useNavigation();
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator
screenOptions={({route}) => ({
tabBarButton: ['Contact', 'Route2ToExclude'].includes(route.name)
? () => {
return null;
}
: undefined,
})}>
<Tab.Screen
name="Home"
component={Home}
/>
<Tab.Screen
name="MyAccount"
component={MyAccount}
/>
<Tab.Screen
name="Cart"
component={Cart}
/>
<Tab.Screen
name="Sidebar"
component={Sidebar}
/>
<Tab.Screen name="Contact" component={Contact} />
</Tab.Navigator>
);
};
const MyDrawerNavigation = () => {
return (
<Drawer.Navigator drawerPosition={'right'}>
<Drawer.Screen
name="Home"
component={MyTabs}
initialParams={{screen: 'Home'}}
/>
<Drawer.Screen
name="My Account"
component={MyTabs}
initialParams={{screen: 'MyAccount'}}
/>
</Drawer.Navigator>
);
};
const styles = StyleSheet.create({
tabNav: {
backgroundColor: '#000000',
},
});
export default Navigator;
You can pass the screen as the initial param and it would redirect to the correct tab.
<Drawer.Screen name="MyTabs" component={'Tab Component Name'} initialParams={{screen:'MyAccount'}}/>
SOLVED!:
After extensively further researching; I have created my own custom Drawer, with the onPress handler.
The onPress handler initiates the action for navigation to the specified screens.
NOTE: you will have to pass in the navigation ref to the top-level navigation container. You will also have to pass this same reference into your custom drawer module (or any module in that concern)
here's my custom drawer component:
import React, {Component} from 'react';
import {Text, View, Button, StyleSheet} from 'react-native';
import {useNavigation, CommonActions} from '#react-navigation/native';
import * as rootNavigator from '../components/rootNavigator';
const CustomDrawer = () => {
return (
<View style={styles.container}>
<Button
title="My Account"
onPress={() => rootNavigator.navigate('MyAccount')}
/>
<Button
title="Contact"
onPress={() => rootNavigator.navigate('Contact')}
/>
<Button title="Cart" onPress={() => rootNavigator.navigate('Cart')} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 30,
},
});
export default CustomDrawer;
here's the code where I return the DrawerNavBar:
const MyDrawerNavigation = () => {
return (
<NavigationContainer ref={navigationRef}>
<Drawer.Navigator
drawerPosition={'right'}
drawerContent={(props) => <CustomDrawer {...props} />}>
<Drawer.Screen name="Tabs" component={MyTabs} />
<Drawer.Screen name="Contact" component={Contact} />
</Drawer.Navigator>
</NavigationContainer>
);
};
I am building an app with one main tab navigator, and then several nested stack navigators within it. All of my navigators are written within the App.js file. The main tab navigator is working fine, however when I attempt to navigate into one of the nested stack navigators I get a TypeError: undefined is not an object (evaluating _this.props.navigation) error.
Here is an example of my code below:
App.js File
import React from 'react;
import {createMaterialBottomTabNavigator} from '#react-navigation/material-bottom-tabs';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import Home from './src/screens/Home';
import Settings from './src/screens/Settings';
import Privacy from './src/screens/Privacy';
const PrivacyStack = createStackNavigator();
const SettingsStack = createStackNavigator();
const AuthStack = createStackNavigator();
const MainStack = createStackNavigator();
const Tabs = createMaterialBottomTabNavigator();
const TabNavigator = () => {
return (
<Tabs.Navigator
initialRouteName="Home"
<Tabs.Screen
name="Home"
component={HomeStack}
/>
Tabs.Screen
name="Settings"
component={SettingsStack}
children={this.SettingsStack}
</Tabs.Navigator>
)
}
const AuthStack = () => (
<AuthStack.Navigator>
<AuthStack.Screen
name="Auth"
component={Auth}
/>
</AuthStack.Navigator>
);
const SettingsStackScreen = () => (
<SettingsStack.Navigator>
<SettingsStack.Screen
name="Settings"
component={Settings}
/>
<SettingsStack.Screen
name="Privacy"
component={PrivacyStack}
/>
</SettingsStack.Navigator>
);
const PrivacyStack = () => (
<PrivacyStack.Navigator>
<PrivacyStack.Screen
name="Privacy"
component={Privacy}
/>
<PrivacyStack.Screen
name="Notifications"
component={Notifications}
/>
</PrivacyStack.Navigator>
);
const App = () => {
return (
<NavigationContainer ref={navigationRef}>
<MainStack.Navigator>
<MainStack.Screen name="Tabs" component={TabNavigator} />
<MainStack.Screen
name="Auth"
component={AuthStack}
options={{gestureEnabled: false}}
/>
</MainStack.Navigator>
</NavigationContainer>
)
}
Settings.js File
import React from 'react';
import {TouchableOpacity} from 'react-native;
const Settings = (navigation, props) => {
return (
<TouchableOpacity onPress={() => this.props.navigation.navigate('PrivacyStack', {screen: 'Privacy'}
)
}
</TouchableOpacity>
export default Settings
Privacy.js File
import React from 'react';
import {TouchableOpacity} from 'react-native;
const Privacy = (navigation, props) => {
return (
<TouchableOpacity onPress={() => this.props.navigation.navigate('Notifications'
)
}
</TouchableOpacity>
export default Privacy
After the user has passed auth, they are taken to the MainStack which has a bottom tab navigator with a Home screen option, and a Settings screen option. This part is all currently working fine. However once I click the <TouchableOpacity> on the Settings screen I get the error.
I suspect it must be an issue with the way I am using this.props.navigation however I have not managed to figure out the problem through my own troubleshooting. Any help would be hugely appreciated.
You are using functional component so you can use the navigation like below
const Settings = (props) => {
return (
<TouchableOpacity onPress={() => props.navigation.navigate('PrivacyStack',
'navigation' is passed as a prop and will reside inside props argument.