how to get drawerOpen() to stack navigator screen Options - react-native

i have this stack navigator:
const StackNavigator = () => (
<Stack.Navigator headerMode="screen" navigationOptions screenOptions={ss}>
<Stack.Screen name="Main" component={MainScreen} headerMode="screen" />...............
and i have object of screen options:
const ss = {
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
gestureEnabled: true,
gestureDirection: "horizontal",
headerTitleAlign: "center",
headerHideShadow: true,
headerTintColor: "red",
headerStyle: {
borderBottomWidth: 0.5,
borderColor: "white",
backgroundColor: "#1d2731",
},
headerTitleStyle: {
color: "white",
},
headerLeft: () => <AnimateHamburger navigation={navigation} />,
};
no when i get inside the component AnimatedHamburger
i dont get the props of openDrawer ...i get "...
navigation.openDrawer is not function....................
the AnimateHamburger component:
const AnimateHamburger = ({ navigation }) => {
console.log(navigation);
const isDrawerOpen = useIsDrawerOpen();
const toggleMenu = () => {
navigation.openDrawer();
};
return (
<View style={styles.icon}>
<Icon
style={styles.icon}
onPress={toggleMenu}
name={isDrawerOpen ? "enter" : "bars"}
type={isDrawerOpen ? "antdesign" : "font-awesome"}
color="black"
size={30}
/>
</View>
);
};
PLEASE help me how can i get the navigation props to toggle my drawer from the AnimateHamburger component

If you receiving openDrawer is not a function that's probably you are trying to access this method in a nested navigator which don't know about the parent drawer navigator. You can access drawer methods with DrawerAction from react-navigation take a look here:
https://reactnavigation.org/docs/drawer-actions
And use it like this:
https://reactnavigation.org/docs/nesting-navigators/#navigator-specific-methods-are-available-in-the-navigators-nested-inside

Related

Can we have different custom drawer contents

I have to Drawer Screens. Both require custom drawer content. I like to know if we can have one custom drawer content for HomeDrawer and a completely different drawer content for the PanelDrawer
<Drawer.Navigator
initialRouteName="HomeDrawer"
edgeWidth={0}
// swipeEdgeWidth={0}
drawerContent={props => <DrawerContent {...props} />}>
<Drawer.Screen
name="HomeDrawer"
options={{
title: headerTitleEnabled ? 'Hello App' : '',
headerStyle: {
backgroundColor: Colors.primary,
},
headerTintColor: '#fff',
headerRight: props => <HeaderButtons {...props} />,
}}
component={MainTabNavigator}
/>
<Drawer.Screen
name="PanelDrawer"
options={{
title: headerTitleEnabled ? 'Hello App' : '',
headerStyle: {
backgroundColor: Colors.primary,
},
headerTintColor: '#fff',
headerRight: props => (
<HeaderButtonsCustom{...props} />
),
}}
component={CustomLayoutNavigator}
/>
Of course, you can nest the drawers if that's the case you want:
Nesting navigators means rendering a navigator inside a screen of another navigator
const MainDrawer = createDrawerNavigator();
const HomeDrawer = createDrawerNavigator();
const PanelDrawer = createDrawerNavigator();
const HomeScreen = () => (
<HomeDrawer.Navigator>
{/*Home drawer custom stuff*/}
</HomeDrawer.Navigator>
);
const PanelScreen = () => (
<PanelDrawer.Navigator>
{/*Panel drawer custom stuff*/}
</PanelDrawer.Navigator>
);
const Navigator = () => (
<MainDrawer.Navigator>
<MainDrawer.Screen name="HomeScreen" component={HomeScreen} />
<MainDrawer.Screen name="PanelScreen" component={PanelScreen} />
</MainDrawer.Navigator>
);
You can read more about nesting navigators in the official documentation.

Set onpress on createDrawerNavigator item in react native?

I have a drawer item "Share App" where I want to open an alert and display a message rather than opening an entire screen in react native. My code is as follows:
const Screen6_StackNavigator = createStackNavigator({
//All the screen from the Screen6 will be indexed here
Sixth: {
screen: ShareApp, //don't want this screen
title:'Share',
navigationOptions: ({ navigation }) => ({
headerLeft: () => <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#138808',
},
headerTintColor: '#fff',
}),
},
});
const DrawerNavigatorExample = createDrawerNavigator({
ShareApp: {
//Title
screen: Screen6_StackNavigator,
navigationOptions: {
drawerLabel: 'Share App',
drawerIcon: (<Entypo name="share" size={20} color='black'></Entypo>)
},
},
);
Where Do I add the onPress parameter in order to call the function? I dont want the screen parameter, want a function to be called only when I click on Share App.
How to do that in react native??
Do help as I am new in React native development....
Thanks.
You can create a custom drawer content component and pass it to the contentComponent option in the DrawerNavigatorConfig.
Creating the custom drawer content:
const CustomDrawerContentComponent = (props) => (
<ScrollView>
<SafeAreaView
style={{ flex: 1 }}
forceInset={{ top: 'always', horizontal: 'never' }}>
<TouchableOpacity
onPress={() => {
// Do something...
Alert.alert('Heading', 'Body');
}}
style={{ left: 15, flexDirection: 'row', alignItems: 'center' }}>
<Entypo name="share" size={20} color='black'></Entypo>
<Text style={{ marginLeft: 30, fontWeight: 'bold' }}>Share App</Text>
</TouchableOpacity>
<DrawerItems {...props} />
</SafeAreaView>
</ScrollView>
);
The DrawerItems component will render clickable drawer options based on the screens you create, but above the DrawerItems we can add your share button for example.
Passing the custom drawer content component to contentComponent
const DrawerNavigatorExample = createDrawerNavigator(
{
Screen1: {
// Properties...
},
// Other screens...
},
{
// Pass custom drawer content component...
contentComponent: props => <CustomDrawerContentComponent {...props} />,
// Other configurations...
},
);
DrawerItems should be imported from react-navigation-drawer.

Passing data from one page to another via StackNavigator in DrawerNavigator

For a hobby project I am building an app where my friends can check out our planned group events. Whenever someone presses on an event I want to show a screen with details about that specific event. So I want to go from my EventScreen which shows a FlatList with Events, to EventDetailScreen. Which needs to show one specific event.
So far I've got the navigation part working, but I cannot pass any data to the next screen...
I have tried to send the event as a param several ways. But I can't figure out what to do next. I've read something about needing to pass data from my DrawerNavigator to my StackNavigator, but when I tried this I got an error saying I need to define my navigation in the AppContainer.
MenuNavigator.js
//Navigation Drawer Structure for all screen
class NavigationDrawerStructure extends Component {
//Top Navigation Header with Donute Button
toggleDrawer = () => {
//Props to open/close the drawer
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
<Ionicons
name="md-menu"
color="white"
size={32}
style={styles.menuIcon}
/>
</TouchableOpacity>
</View>
);
}
}
//Stack Navigator for the First Option of Navigation Drawer
const HomeScreen_StackNavigator = createStackNavigator({
//All the screen from the First Option will be indexed here
HomeScreen: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#000',
},
}),
},
});
//Stack Navigator for the Second Option of Navigation Drawer
const EventsScreen_StackNavigator = createStackNavigator({
//All the screen from the Second Option will be indexed here
EventsScreen: {
screen: EventsScreen,
navigationOptions: ({ navigation }) => ({
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#000',
},
}),
},
});
//Stack Navigator for the Third Option of Navigation Drawer
const CalendarScreen_StackNavigator = createStackNavigator({
//All the screen from the Third Option will be indexed here
CalendarScreen: {
screen: CalendarScreen,
navigationOptions: ({ navigation }) => ({
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#000',
},
}),
},
});
//Stack Navigator for the Fourth Option of Navigation Drawer
const PollScreen_StackNavigator = createStackNavigator({
//All the screen from the Third Option will be indexed here
PollScreen: {
screen: PollScreen,
navigationOptions: ({ navigation }) => ({
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#000',
},
}),
},
});
//Stack Navigator for the Fifth Option of Navigation Drawer
const InfoScreen_StackNavigator = createStackNavigator({
//All the screen from the Third Option will be indexed here
InfoScreen: {
screen: InfoScreen,
navigationOptions: ({ navigation }) => ({
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#000',
},
}),
},
});
//Stack Navigator for the EventDetailScreen of Navigation Drawer
const EventDetailScreen_StackNavigator = createStackNavigator({
//All the screen from the Third Option will be indexed here
EventDetailScreen: {
screen: EventDetailScreen,
navigationOptions: ({ navigation }) => ({
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#000',
},
}),
},
});
const DrawerMenu = createDrawerNavigator(
{
HomeScreen: {
screen: HomeScreen_StackNavigator,
},
EventsScreen: {
screen: EventsScreen_StackNavigator,
},
CalendarScreen: {
screen: CalendarScreen_StackNavigator,
},
PollScreen: {
screen: PollScreen_StackNavigator,
},
InfoScreen: {
screen: InfoScreen_StackNavigator,
},
EventDetailScreen: {
screen: EventDetailScreen_StackNavigator,
},
},
{
// define customComponent here
contentComponent: CustomSidebarMenu,
drawerWidth: 300,
drawerBackgroundColor: 'rgba(0,0,0,0.6)', // or 'rgba(0,0,0,0)'
}
);
const styles = StyleSheet.create({
menuIcon: {
marginLeft: 15,
},
});
export default createAppContainer(DrawerMenu);
Events.js
class EventsScreen extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: null,
refreshing: false,
};
}
async componentDidMount() {
const events = await ajax.FetchEvents();
this.setState({
isLoading: false,
dataSource: events,
refreshing: false,
});
}
handleRefresh = () => {
this.setState(
{
refreshing: false,
},
() => {
this.componentDidMount();
}
);
};
itemCard({ item }) {
const { navigate } = this.props.navigation;
return (
<TouchableWithoutFeedback
onPress={() =>
navigate('EventDetailScreen', {
data: 'test',
})
}>
<View style={styles.card}>
<View style={styles.item}>
<Text style={styles.title}>{item.title}</Text>
<Text numberOfLines={1} style={styles.desc}>
{item.description}
</Text>
<View style={styles.row}>
<View style={styles.iconColumn}>
<Ionicons name="md-home" color="white" size={24} />
</View>
<View style={styles.textColumn}>
<Text style={styles.location}>location</Text>
</View>
</View>
<View style={styles.row}>
<View style={styles.iconColumn}>
<Ionicons name="md-calendar" color="white" size={24} />
</View>
<View style={styles.textColumn}>
<Text style={styles.date}>{item.date}</Text>
</View>
</View>
</View>
</View>
</TouchableWithoutFeedback>
);
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
} else {
return (
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
renderItem={({ item }) => this.itemCard({ item })}
keyExtractor={item => item.id.toString()}
onRefresh={() => this.handleRefresh()}
refreshing={this.state.refreshing}
/>
</View>
);
}
}
}
EventDetailScreen.js
class EventDetailScreen extends Component {
render() {
let item = this.props.navigation.getParam('data', 'NO-DATA');
return (
<View>
<Text>{item}</Text>
</View>
);
}
}
export default EventDetailScreen;
Whenever I click on an event, the EventDetailScreen will say 'NO-DATA' as the item is undefined. My intention is to pass the event, the user clicked on, to the next screen. So I can use the title, description etc. from that specific event.
And yes, I know the code is a bit messy. I'm new to React-Native and this is my first app (and also first post), so there's a lot to improve :)
Thanks in advance!
Found out I should use this.props.navigation.push instead of navigate. This way I can pass params to the next screen. Thanks!
For Passing Param
this.props.navigation.navigate('Filter', {
uri: this.state.uri,
});
For Getting Param
const { navigation } = this.props;
const uri = navigation.getParam('uri');
console.log('url', uri);
this.setState({ uri: uri });
When you called setState() its re-render the component. when component renders its make call of the component's lifecycle( eg. componentWillUpdate or componentDidUpdate).
You might be getting the error because you might be setting state in any of the lifecycles methods. Thus it creates a recursive function calls and you reach Maximum update depth exceeded error.
Rahul Jograna's answer is correct.
refer this link for understanding react-native component lifecycle. https://reactjs.org/docs/react-component.html

How to customize headerLeft React Navigation?

How can I customize headerLeft TabNavigator of React Navigation.
Here's one of my screens :
I want to remove the Back from the headerLeft
Is it possible ?
Here's my code :
DetailTabs = TabNavigator({
DetailResult:{
screen:DetailResult,
navigationOptions:{
title:'Detail Penginapan',
headerTitleStyle:{
fontSize:14,
textAlign: "center",
flex: 1,
},
tabBarVisible: false,
headerStyle:{
backgroundColor:'#4A94FB',
borderBottomColor: 'transparent',
},
headerTintColor: 'white'
}
}
})
By default, HeaderBackButton component is used. You can implement it and use it to override the back button styles, press props, for example:
link to docs
import { HeaderBackButton } from '#react-navigation/stack';
//in newer versions use:
//import {HeaderBackButton} from '#react-navigation/elements';
const styles = StyleSheet.create({
custom: {
// Custom styles here
}
});
<Screen
name="Home"
component={HomeScreen}
options={{
headerLeft: (props) => (
<HeaderBackButton
{...props}
style={styles.custom}
onPress={() => {
// Do something
}}
/>
),
}}
/>;
If you want full control, you can use your custom back button component, example:
import { CustomBackButton } from 'path/to/custom/component';
<Screen
name="Home"
component={HomeScreen}
options={{
headerLeft: (props) => (
<CustomBackButton {...props} />
),
}}
/>;
You probably just need to set headerBackTitle to null. Check out the docs for headerLeft for more info.
Like this:
DetailTabs = TabNavigator({
DetailResult:{
screen:DetailResult,
navigationOptions:{
title:'Detail Penginapan',
headerTitleStyle:{
fontSize:14,
textAlign: "center",
flex: 1,
},
tabBarVisible: false,
headerStyle:{
backgroundColor:'#4A94FB',
borderBottomColor: 'transparent',
},
headerTintColor: 'white',
headerBackTitle: null,
}
}
})
Key is to put this code from where the back button is clicked, not in App.js
In sample below, for Icon to work, use import Icon from 'react-native-vector-icons/Feather';
constructor(props) {
super(props);
this.state = {
// what ever
};
this.props.navigation.setOptions({
headerLeft: () => (
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Home')}
>
<Icon style = {{paddingLeft : 10}} name="arrow-left" size={26} color="black" />
</TouchableOpacity>
),
});
}

DrawerNavigator cant set background to transparent whatever I do?

I have spend more than si hours trying to change the background of the DrawerNavigator to transparent without any success.
When I write
when I change it in the main component it works
const MainTabBarDrawer = DrawerNavigator({
Home:{
screen:MainTabNavigator,
},
},{
drawerWidth: 200,
drawerPosition: 'right',
// contentComponent: props => <Text style={{color:'white'}} >text
</Text>,
drawerBackgroundColor: 'yellow',
//backgroundColor:'transparent',
// style: {
// //backgroundColor: 'transparent',
// flex: 1
// },
// contentOptions: {
// style: {
// backgroundColor: 'transparent',
// flex: 1
// }
},
{
style: {
backgroundColor: 'transparent',
flex:1
}
}
)
class App extends Component{
render()
{
return(<MainTabBarDrawer style={{backgroundColor: 'transparent'}}/>)
//return(<Login/>)
}
}
While the above approach will work my layout is much complex and I don't want the drawer to appear in all my views.
So dose any body know If I can change the background of the DrawerNavigator directly without rendering it as a component?
In React Navigation 5, this would be:
<Drawer.Navigator
initialRouteName={...}
drawerContent={...}
drawerStyle={{backgroundColor: 'transparent'}}
>
Add drawerBackgroundColor: "transparent" to drawerConfig.
I think you are looking for drawerContentOptions or drawerStyle of Drawer.Navigator
<NavigationContainer>
<Drawer.Navigator
..........
drawerPosition="left"
drawerContentOptions={{
activeBackgroundColor:"transparent", //here change it
}}
drawerStyle={{backgroundColor: 'transparent'}} //or here
initialRouteName="Splash">
<Drawer.Screen
name="HomePage"
component={StackScreen}
options={{
drawerLabel: () => {return null},
title:null,
drawerIcon: () => {return <AppIconImage/>}
}}
/>
</Drawer.Navigator>
</NavigationContainer>
The issue was fixed since I have updated to the latest version
1.0.0-beta.16
Adding the style backgroundColor: 'transparent' to drawerStyle inside the screenOptions param of Drawer.Navigator worked for me.
import React from 'react';
import {createDrawerNavigator} from '#react-navigation/drawer';
import CustomDrawer from '../components/Drawer';
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<Drawer.Navigator
initialRouteName="Stack"
screenOptions={{
headerShown: false,
drawerStyle: {width: '80%', backgroundColor: 'transparent'}, // Add this.
}}
drawerContent={props => <CustomDrawer {...props} />}>
// Screens that go inside the navigator.
</Drawer.Navigator>
);
};
export default DrawerNavigator;
P.S.: I am using #react-navigation/drawer: ^6.5.0.
For ReactNavigation Version 6.
try
<Drawer.Navigator
initialRouteName={...}
drawerContent={...}
screenOptions={{
drawerStyle: {
backgroundColor: 'transparent',
},
}}>
Adding React Docs link for reference.
https://reactnavigation.org/docs/drawer-navigator#drawerstyle