Add hamburger button to React Native Navigation - react-native

I'm very new to React-Native so I definitely may be missing something. But all I want to do is add a hamburger type button to a settings page in the main Navigation bar. I have set up a link in the main part of that works the way I want hamburger button to work.
Screenshot
import React from 'react';
import { AppRegistry, Text, View, Button } from 'react-native';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
headerLeft: <Button onPress={ WHAT GOES HERE?? } title= "=" />
};
render() {
const { navigate } = this.props.navigation;
return (
<Button
onPress={() => navigate('Settings')}
title="Link to Settings" />
);
}
}
class Settings extends React.Component {
static navigationOptions = {
title: 'Settings',
headerLeft: <Button title= "=" />
};
render() {
return <Text>Hello, Settings!</Text>;
}
}
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
Settings: { screen: Settings}
});
AppRegistry.registerComponent('NavPractice', () => SimpleApp);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Having this, you're very close to the solution.
static navigationOptions = {
title: 'Welcome',
headerLeft: <Button onPress={ WHAT GOES HERE?? } title= "=" />
};
A little-known fact is that navigationOptions accepts a function that returns navigation options. That function accepts some props, navigation one of them. Know this, adjust your code a little.
static navigationOptions = function(props) {
return {
title: 'Welcome',
headerLeft: <Button onPress={() => props.navigation.navigate('DrawerOpen')} title= "=" />
}
};

check this link with same issue https://github.com/react-community/react-navigation/issues/1539
check navigationOptions
navigationOptions: ({ navigation }) => ({
title: 'Schedules', // Title to appear in status bar
headerLeft: <Icon name="menu" size={35}
onPress={ () => navigation.navigate('DrawerOpen') } />
from
const SchedulesStack = StackNavigator({
Schedules: {
screen: SchedulesScreen,
navigationOptions: ({ navigation }) => ({
title: 'Schedules', // Title to appear in status bar
headerLeft: <Icon name="menu" size={35} onPress={ () => navigation.navigate('DrawerOpen') } />
})
}
});
const Homestack = StackNavigator({
Home: {
Screen: Home
navigationOptions: ({ navigation }) => ({
title: 'Home', // Title to appear in status bar
headerLeft: <Icon name="menu" size={35} onPress={ () => navigation.navigate('DrawerOpen') } />
})
}
});
const Root = DrawerNavigator({
Home: {
screen: HomeStack,
navigationOptions: {
title: 'Home' // Text shown in left menu
}
},
Schedules: {
screen: SchedulesStack,
navigationOptions: {
title: 'Schedules', // Text shown in left menu
}
}
}
})

In the above code it seems you are adding options to the sidebar and navigating to the sidebar menus.
//sidebar menu no.1
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
headerLeft: <Button onPress={//action taken when option in the menu bar is clicked} title= "//the title of the screen where you will navigate and the sidebar menu lable" />
};
render() {
const { navigate } = this.props.navigation;
return (
<Button
onPress={() => navigate('Settings')}
title="Link to Settings" />
);
}
}
In this way you can create as many drawer options as you can.. now how to combine drawer options:
//react navigation provides you with DrawerNavigator API
const MyApp = DrawerNavigator({
Home: {
screenA: HomeScreen ,
},
Settings: {
screen: MySettingScreens,
},
});
The drawer also comes with a prop that is screenProps={/* this prop will get passed to the screen components and nav options as props.screenProps */}, like this :
<MyApp
screenProps={/* this prop will get passed to the screen components and nav options as props.screenProps */}
/>
Following are the props that react navigator provide to open/close drawer.
this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer
You can also set the drawer style according to you, like this:
drawerWidth - Width of the drawer
drawerPosition - Options are left or right. Default is left position.
contentComponent - By default there is no scrollview available in the drawer. In order to add scrollview in the drawer you need to add contentComponent in the configuration.
contentOptions - As the name suggest these are used to give color to the active and inactive drawer items (label).
Cheers :)

Related

Is there anyway to turn `options` into a function same like `navigationOptions` do?

Currently, I was taking a course:Multiplatform Mobile App Development with React Native in coursera, and I was stuck at after every lecture because the instructor use react-navigation#2.0.1 but I want to make sure to learn the latest version(v5). In this lecture he created a stack navigator and bring an icon to a screen like,
import {createStackNavigator} from 'react-navigation';
import { Icon } from 'react-native-elements';
const MenuNavigator = createStackNavigator(
{
Menu: {
screen: Menu,
navigationOptions: ({ navigation }) => ({
headerLeft: (
<Icon
name="menu"
size={24}
color="white"
onPress={() => navigation.toggleDrawer()}
/>
),
}),
},
Dishdetail: { screen: Dishdetail },
},
{
initialRouteName: 'Menu'
}
);
Where navigationOptions can be an object or be a function that takes in props.
I convert it like,
import { createStackNavigator } from '#react-navigation/stack';
import { Icon } from 'react-native-elements';
const MenuNavigator = createStackNavigator();
function MenuNavigatorScreen() {
return (
<MenuNavigator.Navigator
initialRouteName="Menu"
screenOptions={HeaderOptions}
>
<MenuNavigator.Screen
name="Menu"
component={Menu}
/>
<MenuNavigator.Screen
name="Dishdetail"
component={Dishdetail}
options={{ headerTitle: 'Dish Detail' }}
/>
</MenuNavigator.Navigator>
);
}
But I was confused how to convert the navigationOptions functionality into my code. Because their docs didn't tell how to trun my options object into a function to bring the navigation prop?
One more thing is he was using drawerIcon,
const MainNavigator = createDrawerNavigator(
{
navigationOptions: {
drawerLabel: 'Login',
drawerIcon: ({ tintColor }) => (
<Icon
name="sign-in"
type="font-awesome"
size={24}
color={tintColor}
/>
),
}
...
But I didn't find anything related drawerIcon in Drawer navigation docs
I heartily thank if anyone helps me to figure out this.
First of all, The options prop can be used to configure individual screens inside the navigator. And headerLeft is a function that returns a React element to display on the left side of the header. When a function is used, it receives several arguments when rendered (onPress, label, labelStyle, and more - check types.tsx for the complete list).
options = {
({
navigation
}) => ({
headerLeft: () => ( <
Icon name = 'menu'
size = {
24
}
color = 'white'
onPress = {
() =>
navigation.toggleDrawer()
}
/>
)
})
}
And for drawerIcon use:
options = {
{
drawerIcon: ({
tintColor
}) => ( <
Icon name = 'home'
type = 'font-awesome'
size = {
24
}
color = {
tintColor
}
/>
)
}
}

Navigation drawer is not opening and toggleDrawer not found

Trying to create drawer using React-Navigation.
Using React Native 0.59, Installed React-Navigation 3.x, has done linking react-native link react-native-gesture-handler.
Create routes using React-Navigation, called Route.js:
const Drawer = createDrawerNavigator(
{
Settings: {
screen: HomeScene,
navigationOptions: {
title: 'Home',
drawerIcon: () => (
<Icon name="home" style={{ color: colors.white, fontSize: 24 }} type="Ionicons" />
)
}
}
},
{
contentComponent: props => <GlobalSideMenu {...props} />
}
);
const AppNavigator = createStackNavigator(
{
Home: {
screen: HomeScene,
navigationOptions: {
header: null
}
},
Drawer: {
screen: Drawer,
navigationOptions: {
header: null
}
}
},
{
initialRouteName: 'Home'
}
);
export default createAppContainer(AppNavigator);
Then in the header, drawer icon:
<Button icon transparent onPress={() => this.props.navigation.toggleDrawer()}>
<Icon name={icon('menu')} type="Ionicons" style={styles.menuColor} />
</Button>
It gives me error : toggleDrawer() is undefined.
Then I change it to :
this.props.navigation.dispatch(DrawerActions.toggleDrawer());
Now, there is no error, but the drawer is not opening.
This is usually the case if you are attempting to open the drawer from outside the drawer navigator's set of screens.
this.props.navigation.toggleDrawer is only defined if you are in Settings, which I guess is not the case.
You can either rearrange the navigation so that the drawer is present on the screen you are calling toggleDrawer from, or you can navigate to Settings first.
<Button
icon
transparent
onPress={() => {
this.props.navigation.navigate('Settings');
this.props.navigation.dispatch(DrawerActions.openDrawer());
}}
>
<Icon name={icon('menu')} type="Ionicons" style={styles.menuColor} />
</Button>
Here is an example to clarify.

Dynamically change header title in react native navigation

For a school assignment we're creating an app in react native with react navigation and redux. Because all of us are new to react we have an issue we are unable to resolve.
We want to change the title of the header when a certain button is clicked. The first time we click a button it changes the header title just fine. The problem arrises when we press a different button, the header doesn't change. Note that no matter what option we choose, we always go to the same screen.
import React from 'react';
import { createStackNavigator, createAppContainer, createDrawerNavigator } from 'react-navigation';
import {connect} from 'react-redux';
import { store } from '#redux/MyStore';
import { Ionicons } from '#expo/vector-icons';
import ScannerScreen from '#screens/ContactScreen';
import EventsScreen from '#screens/ListScreen';
const ContactStack = createStackNavigator({
Contact: {
screen: ContactScreen,
navigationOptions: ({navigation}) => ({
headerStyle: {backgroundColor: '#fa8231'},
headerTitleStyle: {fontSize: 18},
title: store.getState().setupState.title,
headerLeft: <Ionicons
name="md-menu" style={{marginLeft:10}}
size={28}
onPress={() => navigation.toggleDrawer()} /> //menu button
})
}
});
// Code to create stack for the ListStack
const DrawerStack = createDrawerNavigator({
Contact: ContactStack,
List: ListStack
});
const PrimaryNavigation = createStackNavigator({
ListStack: {
screen: ListStack,
navigationOptions: {
header: null,
},
},
DrawerStack: {
screen: DrawerStack,
navigationOptions: {
header: null,
},
},
},
{
initialRouteName: 'ListStack',
});
const AppContainer = createAppContainer(PrimaryNavigation);
class AppNavigation extends React.Component {
render() {
return <AppContainer/>
}
}
export default (AppNavigation)
We did get it working when we put the title bar in the DrawerNavigator, but since we want the Drawer in from of the header that is not an option. My speculation is that the stack is created once with a certain title and never gets updated when switching screens using the DrawerNavigator but we have no clue how to fix that.
Thanks in advance!
From what I understand you need to change the title when a screen is loaded in stack.So you could use some like:
class ScreenInContactStack extends React.Component{
//Constryctor
static navigationOptions = ({navigation}) => ({
title: (navigation.state.params || {}).title || 'Chat! ',
});
//Remaining Logic
}
and while calling
this.props.navigation.navigate('ScreenInContactStack', {title: yourTitle + ' ',});
Don't know why but the Appbar condense the title to like yourTi.. to avoid this add a space to the title.
Try this:
map title as a prop to force ContactStack to re-render whenever it changes
class ContactStack extends React.Component {
render() {
const { title } = this.props.setupState;
const Stack = createStackNavigator({
Contact: {
screen: ContactScreen,
navigationOptions: ({navigation}) => ({
headerStyle: {backgroundColor: '#fa8231'},
headerTitleStyle: {fontSize: 18},
title,
headerLeft: <Ionicons
name="md-menu" style={{marginLeft:10}}
size={28}
onPress={() => navigation.toggleDrawer()} /> //menu button
})
}
});
return <Stack />;
}
}
const mapStateToProps = ({ setupState }) => ({setupState});
export default connect(mapStateToProps)(ContactStack);

How to change screen using stackNavigation in React Native?

I have one screen which in header consists button to go to another screen.
I have already model here, but it doesn't work: As shown below I want to change the screen from RecipeList to NewRecipeForm using Button in header
const AppStackNavigator = createStackNavigator({
List: {
screen: RecipesList,
navigationOptions: {
title:'RecipesList',
headerLeft: (
<Button onPress={()=>this.props.navigation.navigate('NewRecipeForm')}>
<Text>+</Text>
</Button>
)
}},
NewRecipeForm: {screen: CreateRecipeForm,
navigationOptions: {title:'Add new recipe'}},
Details: {screen: RecipesDetails, navigationOptions: {title:'RecipeDetails'}},
export default class App extends React.Component {
render() {
return <AppStackNavigator initialRouteName='List' />;
}
}
I hope that you will help me with solution
You may use your stack navigator as like below, you can able to destructure your navigation property while giving your navigationOptions property as well in the createStackNavigator itself
const AppStackNavigator = createStackNavigator({
List: {
screen: RecipesList,
navigationOptions: ({navigation}) => { //destructure the navigation property here
return {
title: 'RecipesList',
headerLeft: (
<Button onPress={() => navigation.navigate('NewRecipeForm')}>
<Text>+</Text>
</Button>
)
}
}
},
NewRecipeForm: {
screen: CreateRecipeForm,
navigationOptions: { title: 'Add new recipe' }
},
Details: { screen: RecipesDetails, navigationOptions: { title: 'RecipeDetails' } }
});
You cannot access the props of your component in headerLeft, but you can directly use the navigation like this :
<Button onPress={()=> navigation.navigate('NewRecipeForm')}>
You can use following code inside your RecipesList Component instead of having it inside createStackNavigator(). See this Snack for full implementation.
static navigationOptions = ({ navigation }) => {
return {
headerTitle: "RecipesList",
headerLeft: (
<Button
onPress={() => navigation.navigate('NewRecipeForm')}
title="+"
/>
),
};
};

The menu si rendered offscreen when clicked from the left button of the navigation bar

Is there a way to have the menu render left-to-right instead of right-to-left?
When clicked from the right button of the navigation bar, it's ok;
instead from the left button, it's rendered off screen.
Here is a short example how to use popup menu with react-navigation. The menu is rendered in both headerRight and headerLeft placeholders. It is displayed correctly on both sides:
import React from 'react';
import { AppRegistry, Text } from 'react-native';
import { StackNavigator } from 'react-navigation';
import Menu, {
MenuContext,
MenuOptions,
MenuOption,
MenuTrigger
} from 'react-native-popup-menu';
const NavigatorMenu = ({ navigation }) => (
<Menu>
<MenuTrigger text='...' />
<MenuOptions>
<MenuOption
onSelect={() => navigation.navigate('Page2')}
text='Navigate Page 2'
/>
<MenuOption
onSelect={() => navigation.navigate('Page3')}
text='Navigate Page 3'
/>
</MenuOptions>
</Menu>
);
class Home extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: 'Home',
headerRight: <NavigatorMenu navigation={navigation} />,
headerLeft: <NavigatorMenu navigation={navigation} />,
});
render() {
return <Text>Home Page</Text>;
}
}
const Page2 = () => <Text>2nd Page</Text>;
const Page3 = () => <Text>3rd Page</Text>;
const TopStackNavigator = StackNavigator({
Home: { screen: Home },
Page2: { screen: Page2 },
Page3: { screen: Page3 },
});
const App = () => (
<MenuContext>
<TopStackNavigator />
</MenuContext>
);
AppRegistry.registerComponent('examples', () => App);
It was tested on android with:
react-native: 0.37.0
react-native-popup-menu: 0.7.3
react-navigation: 1.0.0-beta
Solved. During testing i was mixing react-native-menu and react-native-popup-menu. I had both installed. And Webstorm pulled me in imports for both libraries mixing them up.