How to implement a Drawer navigator in react native? - react-native

Hi i 'm new to react native how to implement a drawer navigator in react native. Actually i'm following this doc
Updated:
code for home page is as follows
constructor(props){
super(props)
this.state= {
icon: null
}
}
render(){
return(
<Container>
<Header style={{backgroundColor:'pink'}} >
<Button
transparent
onPress= {() => this.props.navigation.navigate("DrawerOpen")}>
<Icon
style= {{color: '#ffffff', fontSize:25, paddingTop:0}}
name="bars"
/>
</Button>
</Header>
<Content>
</Content>
</Container>
);
}
}
also
index.js
import CourseListing from './CourseListing';
import SideBar from './SideBar/SideBar';
import {DrawerNavigator} from 'react-navigation';
import Profile from './Profile';
const MyHome =DrawerNavigator(
{
CourseListing: {screen: CourseListing},
Profile: {screen: Profile},
},
{
contentComponent: props => <SideBar {...props} />
}
);
I'm getting this error

In addition to the documentation which is great, I also recommend watching This video.
I would suggest creating a file called Router.js. It could look something like this:
import React from 'react';
import { DrawerNavigator } from 'react-navigation';
import Screens1 from ... // Import all your screens here
import Screens2 from ...
import Screens3 from ...
// The DrawerNavigator uses all the screens
export const MyDrawer = DrawerNavigator({
Screen1: { screen: Screen1 },
Screen2: { screen: Screen2 },
Screen3: { screen: Screen3 },
});
In your root (usually called App.js) make sure to import MyDrawer:
import React, { Component } from 'react';
import { MyDrawer } from '(correct path here)/Router.js';
export default class App extends Component {
render() {
return <MyDrawer />;
}
}
Now when the app starts Screen1 will be loaded. Each of the screens has a side menu because of the DrawerNavigator. To open the menu in any screen, use the following method:
_openMenu() {
this.props.navigation.navigate('DrawerOpen');
}
Hope this helps.

it's so, implement drawer such as stack-navgation
exmaple :
import { createDrawerNavigator } from 'react-navigation-drawer';
import {signIn,drawer} from 'scene'
const RouteConfigs = {
signIn
}
const DrawerNavigatorConfig = {
drawerPosition:'right',
drawerType:'front',
hideStatusBar:true,
contentComponent:drawer
}
export default createDrawerNavigator(RouteConfigs, DrawerNavigatorConfig);
the important part is contentComponent in DrawerNavigatorConfig. it's a view that shows in the drawer when it opens

import React, { Component } from "react";
import { Dimensions, StyleSheet, } from 'react-native';
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import color from '../../../constants/color'
import Attendance from '../../ExtraScreens/Attendance/Attendance'
import KIETDigitalDirectory from '../../ExtraScreens/KIETDigitalDirectory/KIETDigitalDirectory'
import KIETExtensions from '../../ExtraScreens/KIETExtensions/KIETExtensions'
import StudentRedressal from '../../ExtraScreens/StudentRedressal/StudentRedressal'
//
import Ticketing from '../../ExtraScreens/Ticketing/Ticketing'
import TicketingApply from '../../ExtraScreens/Ticketing/TicketingApply'
//
import Grievance from '../../ExtraScreens/EmployeeGrievance/Grievance'
import GrievanceApply from '../../ExtraScreens/EmployeeGrievance/GrievanceApply'
export default class Extra extends React.Component {
render() {
const Drawer = createDrawerNavigator();
return (
<Drawer.Navigator
drawerType="back"
// openByDefault
// overlayColor="transparent"
>
<Drawer.Screen name="KIET Extensions" component={KIETExtensions} />
<Drawer.Screen name="Grievance" component={GrievanceStack} />
<Drawer.Screen name="Ticketing" component={TicketingStack} />
<Drawer.Screen name="Student Redressal" component={StudentRedressal} />
<Drawer.Screen name="Attendance" component={Attendance} />
<Drawer.Screen name="KIET Digital Directory" component={KIETDigitalDirectory} />
</Drawer.Navigator>
)
}
}
const StackNavigator = createStackNavigator();
const GrievanceStack = (props) => (
<StackNavigator.Navigator
initialRouteName="Grievance"
mode="card"
headerMode="none"enter code here>
<StackNavigator.Screen name="Grievance" component={Grievance} />
<StackNavigator.Screen name="Grievance Apply" component={GrievanceApply} />
</StackNavigator.Navigator>
)
const TicketingStack = (props) => (
<StackNavigator.Navigator
initialRouteName="Ticketing"
mode="card"
headerMode="none"
>`enter code here`
<StackNavigator.Screen name="Ticketing" component={Ticketing} />
<StackNavigator.Screen name="Ticketing Apply" component={TicketingApply} />
</StackNavigator.Navigator>
)

Related

React native navigation not initialized yet

I'm learning react native but I'm having difficulty with navigation, it's returning the error that navigation has not been initialized yet.
I looked for some tutorials, I tried some other ways, I went to the react native navigation documentation and, incredible as it may seem, it's the same as in the documentation... not even the GPT chat haha ​​it didn't help me.
Can someone with experience in react native give me a light?
app.tsx:
import { NavigationContainer } from '#react-navigation/native';
import { createAppContainer } from 'react-navigation';
import StackNavigator from './app/index/navigator';
const AppContainer = createAppContainer(StackNavigator);
const App = () => {
return (
<NavigationContainer>
<AppContainer />
</NavigationContainer>
);
}
export default App;
navigator.tsx?
import { createStackNavigator } from 'react-navigation-stack';
import Index from '.';
import AddNewGrocery from '../components/addNewGrocery'
const StackNavigator = createStackNavigator({
home: { screen: Index, navigationOptions: { headerShown: false } },
addNewGrocery: { screen: AddNewGrocery, navigationOptions: { headerShown: false } },
});
export default StackNavigator;
index.tsx:
const Index = () => {
return (
<View style={styles.container}>
<Text style={styles.title}>Gestão de Compras</Text>
<LastFiveGrocery />
<MonthAverageSpend />
<TotalSpend />
<AddButton />
<StatusBar
translucent={false}
backgroundColor={'rgba(43, 43, 43, 1)'}
barStyle='light-content' />
</View>
);
}
AddButton.tsx:
import React from 'react';
import { StyleSheet, View, TouchableOpacity } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { useNavigation } from '#react-navigation/native';
const AddButton = () => {
const navigation = useNavigation();
const handleAddButtonPress = () => {
navigation.navigate('addNewGrocery' as never);
}
return (
<TouchableOpacity style={styles.addButtonContainer} onPress={handleAddButtonPress}>
<View style={styles.addButton}>
<Ionicons name="ios-add" size={36} color="white" />
</View>
</TouchableOpacity>
);
}
I already tried to use it this way:
AddButton:
const { navigate } = useNavigation<StackNavigationProp<ParamListBase>>();
const handleAddButtonPress = () => {
navigate('addNewGrocery');
}
I've also tried using it this way:
navigator:
const StackNavigator = createAppContainer(createStackNavigator({
Home: { screen: Index },
addNewGrocery: AddNewGrocery,
}));
app.tsx:
import StackNavigator from './app/index/navigator';
const App = () => {
return (
<StackNavigator />
);
}
export default App;
You are using 2 different navigation library in simultaneously:
#react-navigation
react-navigation
Remove react-navigation and refactor the App.js file as below:
import { NavigationContainer } from '#react-navigation/native';
import StackNavigator from './app/index/navigator';
const App = () => {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
);
}
export default App
StackNavigator should be implemented as per documentation -
https://reactnavigation.org/docs/stack-navigator/#api-definition

How to correctly implement Drawer in native-base in react-native using react-navigation v3

I am newbie to react-native and I will like implement correctly the Drawer in native-base with react native stack navigation. I am sorry my question might be too basic. I just need the proper way to implement it.
Below is my App.js
import React, {Component} from 'react';
import { AppLoading } from 'expo';
import { Container, Text } from 'native-base';
import * as Font from 'expo-font';
import { Ionicons } from '#expo/vector-icons';
import { Header, Title,Accordion, Content, Footer, FooterTab, Button, Left, Right, Body, Icon } from 'native-base';
import FirstScreen from './src/FirstScreen';
import Screen1 from './src/Screen1';
import Screen2 from './src/Screen2';
import Screen3 from './src/Screen3';
import {
createDrawerNavigator,
createStackNavigator,
createAppContainer,
createSwitchNavigator,
DrawerItems
} from 'react-navigation';
const DrawerContent = (props) =>(
<View style={{backgroundColor:'red'}}>
<View style={{
backgroundColor:'#f50057',
height:140,
alignItems: 'center',
justifyContent:'center'
}}>
<Text style={{color: 'white',fontSize:30}}>
Header
</Text>
</View>
<DrawerItems/>
</View>
);
const HomeScreenRouter = createDrawerNavigator(
{
Screen1: { screen: Screen1 },
Screen2: { screen: Screen2 },
Screen3: { screen: Screen3 },
},
{
contentComponent: <DrawerContent/>,
}
);
const AuthStack = createStackNavigator(
{
FirstScreen: FirstScreen
}
);
const AppContainer = createAppContainer(createSwitchNavigator(
{
App: HomeScreenRouter,
Auth: AuthStack
},{
initialRouteName: 'Auth',
}
));
export default class App extends Component{
constructor(props){
super(props)
this.state = {
isReady: false
}
}
async componentDidMount(){
await Font.loadAsync({
Roboto: require('native-base/Fonts/Roboto.ttf'),
Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf'),
}).then((err) =>{
this.setState({ isReady: true });
})
}
render(){
if(!this.state.isReady){
return(
<AppLoading/>
)
}
return(
<AppContainer/>
)
}
}
Below is my FirstScreen.js
import React, {Component} from 'react';
import { AppLoading } from 'expo';
import { Container, Text } from 'native-base';
import * as Font from 'expo-font';
import { Ionicons } from '#expo/vector-icons';
import { Header, Title,Accordion, Content, Footer, FooterTab, Button, Left, Right, Body, Icon } from 'native-base';
export default class FirstScreen extends Component{
constructor(props){
super(props);
this.state = {
isReady: false
}
}
render(){
if(!this.state.isReady){
return(
<AppLoading/>
)
}
return (
<Container>
<Header>
<Left>
<Button transparent onPress={() this.props.navigation.openDrawer() }>
<Icon name="menu"/>
</Button>
</Left>
<Body>
<Title>Be in</Title>
</Body>
<Right/>
</Header>
<Content>
</Content>
</Container>
);
}
}
The app doesnt output any error but I got a blank white page with header.
I expect the output to like this
Thanks in advance.
Simple solution for react-navigation v5
import * as React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createDrawerNavigator} from '#react-navigation/drawer';
import {createStackNavigator} from '#react-navigation/stack';
// screens
import HomeScreen from '../screens/HomeScreen';
import CategoryScreen from '../screens/CategoryScreen';
import CartScreen from '../screens/CartScreen';
import MapScreen from '../screens/MapScreen';
import ProfileScreen from '../screens/ProfileScreen';
import SettingsScreen from '../screens/SettingsScreen';
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
function MainStackNavigator() {
return (
<Stack.Navigator headerMode="none" initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Cart" component={CartScreen} />
<Stack.Screen name="Category" component={CategoryScreen} />
<Stack.Screen name="Map" component={MapScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}
export default function AppRouter() {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={MainStackNavigator} />
</Drawer.Navigator>
</NavigationContainer>
);
}

Confusion with react-navigation with react-navigator 3

I am using react-navigation v3 for navigation in my react-native app. When I start app, It navigates to final navigation page i.e. Electonics
AppNavigator.js
import { createStackNavigator, createAppContainer } from 'react-navigation';
import Home from '../container/Home';
import BooksScreen from '../container/BooksScreen'
import ElectronicsScreen from '../container/ElectronicsScreen';
const AppNavigator = createStackNavigator({
Home:Home,
Book: BooksScreen,
Electronics: ElectronicsScreen
});
export default AppContainer = createAppContainer(AppNavigator);
Home.js
import React, { Component } from 'react';
import { View, Text, TouchableOpacity as Button } from 'react-native';
export default class Home extends Component {
render() {
return (
<View>
<Text> Home Page </Text>
<Button
title="Books"
onPress={this.props.navigation.navigate('Book')}
>
</Button>
<Button
title="Books"
onPress={this.props.navigation.navigate('Electronics')}
>
</Button>
</View>
);
}
}
App.js
import AppContainer from './src/Navigation/AppNavigator';
export default class App extends Component {
render() {
console.log(this.props)
return (
<AppContainer />
);
}
}
When I run the code, it runs directly to the ElectronisScreen.js. How can I make it stay at the Home?
Change your AppNavigator to below.
const AppNavigator = createStackNavigator({
Home: Home,
Book: BooksScreen,
Electronics: ElectronicsScreen
},
{
initialRouteName: 'Home',
});
you have to define your initialRouteName.

Tab Navigator - Error: Invalid Key 'tabBar' defined in navigation options

I am trying to get a tab menu to appear using react-navigation (TabNavigator) but I either get the below red screen error or If I change the name of the keys I get a blank screen.
I am using:
react-native: 0.51.0
npm: 4.6.1
This is my router.js file:
import React from 'react';
import { TabNavigator } from 'react-navigation';
import { Icon } from 'react-native-elements';
import BooksList from '../screens/BooksList';
import FilmsList from '../screens/FilmsList';
export const Tabs = TabNavigator({
BooksList: {
screen: BooksList,
navigationOptions: {
tabBar: {
label: "Books",
icon: ({ tintColor }) =>
<Icon name="list" size={35} color={tintColor} />
}
}
}
});
This is my BookList.js file:
import React, { Component } from 'react';
import {
Text,
View,
ScrollView
} from 'react-native';
import { List, ListItem } from 'react-native-elements';
import { users } from '../config/data';
import '../config/ReactotronConfig';
import Reactotron from "reactotron-react-native";
class BooksList extends Component {
onLearnMore = user => {
this.props.navigation.navigate("Details", { ...user });
};
render() {
return (
<ScrollView>
<List>
{users.map(user => (
<ListItem
key={user.login.username}
roundAvatar
avatar={{ uri: user.picture.thumbnail }}
title={`${user.name.first.toUpperCase()} ${user.name.last.toUpperCase()}`}
subtitle={user.email}
onPress={() => this.onLearnMore(user)}
/>
))}
</List>
</ScrollView>
);
}
}
export default BooksList;
Try this.
import React from 'react';
import { TabNavigator } from 'react-navigation';
import { Icon } from 'react-native-elements';
import BooksList from '../screens/BooksList';
import FilmsList from '../screens/FilmsList';
export const Tabs = TabNavigator({
BooksList: {
screen: BooksList,
navigationOptions: {
tabBarLabel: "Books",
tabBarIcon: ({ tintColor }) =>
<Icon name="list" size={35} color={tintColor} />
}
}
});

Why isn't React Native Drawer being triggered using React Native Router Flux + Redux?

I am using the following components to create a React Native + Redux app:
React Native Router Flux
React Native Drawer
I tried following exactly the example provided on how to implement the drawer, yet when navigating to where the drawer should be displayed, using Actions.drawer, I get the error:
But if I try to navigate to the Scene, via Actions.home, inside the drawer Scene, nothing happens but the action REACT_NATIVE_ROUTER_FLUX_RESET is still being called via redux-logger.
Tried following the example exactly but no luck. What could I be doing wrong?
Here is my set up for scene using Redux:
// #flow
import React, { Component } from 'react'
import {
ActionConst,
Actions,
Router,
Scene,
} from 'react-native-router-flux'
import {
Provider,
connect,
} from 'react-redux'
import configureStore from './store/configureStore'
import Login from './components/Login'
import Home from './components/Home'
import NavDrawer from './components/NavDrawer'
const RouterWithRedux = connect()(Router)
const store = configureStore()
export default class App extends Component {
render() {
return (
<Provider store={store}>
<RouterWithRedux>
<Scene key='root'>
<Scene component={Login} initial={true} key='login' title='Login'/>
<Scene key="drawer" component={NavDrawer}>
<Scene component={Home} key='home' title='Home' type='reset' initial={true}/>
</Scene>
</Scene>
</RouterWithRedux>
</Provider>
)
}
}
Then I press a button in Login and it triggers Actions. to navigate to.
The NavDrawer is:
import React, { PropTypes } from 'react'
import Drawer from 'react-native-drawer'
import { Actions, DefaultRenderer } from 'react-native-router-flux'
import NavDrawerPanel from './NavDrawerPanel'
export default class NavDrawer extends Component {
componentDidMount() {
Actions.refresh({key: 'drawer', ref: this.refs.navigation});
}
render() {
const children = state.children;
return (
<Drawer
ref="navigation"
type="displace"
content={<NavDrawerPanel />}
tapToClose
openDrawerOffset={0.2}
panCloseMask={0.2}
negotiatePan
tweenHandler={(ratio) => ({
main: { opacity: Math.max(0.54, 1 - ratio) },
})}
>
<DefaultRenderer
navigationState={children[0]}
onNavigate={this.props.onNavigate}
/>
</Drawer>
);
}
}
And NavDrawerPanel is:
import React from 'react';
import {PropTypes} from "react";
import {
StyleSheet,
Text,
View,
} from "react-native";
import { Actions } from 'react-native-router-flux';
const NavDrawerPanel = (props, context) => {
const drawer = context.drawer;
return (
<View style={styles.container}>
<TouchableHighlight onPress={Actions.home}>
<Text>Home Page</Text>
</TouchableHighlight>
<TouchableHighlight onPress={Actions.login}>
<Text>Login Page</Text>
</TouchableHighlight>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 30,
backgroundColor: 'black'
},
})
EDIT
Here are what's being imported where the Scene + Redux is set up:
// #flow
import React, { Component } from 'react'
import {
ActionConst,
Actions,
Router,
Scene,
} from 'react-native-router-flux'
import {
Provider,
connect,
} from 'react-redux'
import configureStore from './store/configureStore'
import Login from './components/Login'
import Home from './components/Home'
import NavDrawer from './components/NavDrawer'
EDIT 2 - console.log(this.props)
Doing console.log(this.props) in component Login:
When Actions.home() from component Login:
When Actions.drawer() from component Login:
EDIT 3 - console.log(this.props) inside NavDrawer.js
The NavDrawer never gets rendered so console.log(this.props) doesn't get logged
But with console.log(this.props) inside NavDrawer.js and Actions.home, I get:
And with console.log(this.props) inside NavDrawer.js and Actions.drawer, I get:
I'm not an expert in this but I'm using react-native-router-flux and react-native-drawer in my application without any problems. Some of the differences I see between your code and mine are:
You have two scenes set to initial={true}. This might mess up the Router.
I don't navigate directly to the drawer using Actions.drawer but instead I navigate to the home scene using Actions.home.
If nothing of these works, could you share the render() function of your home component?
Not sure if this is the issue but you don't seem to be importing TouchableHighlight on the NavDrawerPanel component, so:
import {
StyleSheet,
Text,
View,
TouchableHighlight
} from "react-native";
I think you pass in wrong value to navigationState in DefaultRenderer.
It should be
const { navigationState: { children } } = this.props;
In your NavDrawer class
import React, { PropTypes } from 'react'
import Drawer from 'react-native-drawer'
import { Actions, DefaultRenderer } from 'react-native-router-flux'
import NavDrawerPanel from './NavDrawerPanel'
export default class NavDrawer extends Component {
componentDidMount() {
Actions.refresh({key: 'drawer', ref: this.refs.navigation});
}
render() {
//const children = state.children; //wrong
const { navigationState: { children } } = this.props;
return (
<Drawer
ref="navigation"
type="displace"
content={<NavDrawerPanel />}
tapToClose
openDrawerOffset={0.2}
panCloseMask={0.2}
negotiatePan
tweenHandler={(ratio) => ({
main: { opacity: Math.max(0.54, 1 - ratio) },
})}
>
<DefaultRenderer
navigationState={children[0]}
onNavigate={this.props.onNavigate}
/>
</Drawer>
);
}
}
Not sure if this is still something you're working on, but for any others using these libraries, you definitely don't want to use the drawer as a scene. It should wrap you whole router like so:
<Drawer
ref={(ref) => { this.drawer = ref; }}
type="displace"
useInteractionManager
content={
<SideMenuContent
open={this.state.sideMenuOpen}
openDrawer={this.openDrawer}
closeDrawer={this.closeDrawer}
/>
}
tapToClose
openDrawerOffset={0.08}
negotiatePan
onOpenStart={() => { this.setState({ sideMenuOpen: true }); }}
onClose={() => { this.setState({ sideMenuOpen: false }); }}
>
<RouterWithRedux
scenes={this.scenes}
/>
</Drawer>
That's how we have it wired up, and it works well. Then, we just pass these function into our scenes as needed:
openDrawer = () => {
this.drawer.open();
}
closeDrawer = () => {
this.drawer.close();
}