I am developing an app using react-native-navigation and I want to have a StackNavigator and a DrawerNavigator in the project. So, I have implemented them in the app.js but the apps crashes giving this error "The development server returned response error with code: 500".I have implemented them separetly and it works but I couldn't implement them together.Any suggestion?
this is my code for app.js
import React, {
Component
} from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
import {
createStackNavigator,
DrawerNavigator,
DrawerItems
} from "react-navigation";
import {
Container,
Header,
Content,
Thumbnail,
Button,
Body
} from 'native-base';
import Profile from './components/Profile.js';
import Main from './components/Main.js';
import Login from './components/Login.js';
import Product from './components/Product.js';
export default class App extends Component {
render() {
return (
<Navapp />
);
}
}
const styles = StyleSheet.create({
// styles here
});
export const Drawer = DrawerNavigator({
Main: {
screen: Main
},
Profile: {
screen: Profile
},
}, {
initialRouteName: 'Main',
contentComponent: CustomDrawer,
drawerPosition: 'Left',
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});
export const CustomDrawer = (props) => (
<Container>
<Header style = {
styles.headerStyle
}>
<Body style = {
styles.bodyStyle
}>
<Thumbnail style = {
{
height: 100,
width: 100
}
}
source = {
require('../image/logo.png')
}/>
</Body>
</Header>
<Content>
<DrawerItems { ...props} />
</Content >
</Container>
)
export const Navapp = createStackNavigator({
Login: {
screen: Login
},
Drawer: {
screen: Drawer
},
Product: {
screen: Product
},
});
I had a very similar setup for my app, this is how I went about handling it. First I created a stack navigator with the routes that I wanted logged in users to see, and I place that navigator inside a drawer navigator (you can put more than one in there if you want). Finally I created my top-level navigator, whose initial route points to the login page; upon logging in I navigate the user to the second route, which points to my drawer navigator.
In practice it looks like this:
// Main Screens for Drawer Navigator
export const MainStack = StackNavigator({
Dashboard: {
screen: Dashboard,
navigationOptions: {
title: 'Dashboard',
gesturesEnabled: false,
headerLeft: null
}
},
Notifications: {
screen: Notifications,
navigationOptions: {
title: 'Notifications'
}
}
}, { headerMode: 'screen' } );
// Drawer Navigator
export const Drawer = DrawerNavigator({
MainStack: {
screen: MainStack
}
});
// Main App Navigation
export const AppStack = StackNavigator({
Login: {
screen: Login,
navigationOptions: {
header: null,
gesturesEnabled: false
}
},
Drawer: {
screen: Drawer,
navigationOptions: {
header: null,
gesturesEnabled: false
}
}
}, { headerMode: 'none' } );
// In Your App.js
<AppStack />
Note that in the last stack navigator, the drawer screen has header set to null; this is because with nested stack navigators you can sometimes run into an issue where you'll have duplicate headers. This will hide the top-level navigator's header and let you show / customize the headers for your nested navigators.
Probably the way we can implement both Stack and Drawer Navigation has been made much simpler. Here you guys can refer to my code.
import * as React from "react";
import { createStackNavigator } from "#react-navigation/stack";
import { createDrawerNavigator } from "#react-navigation/drawer";
import MenuComponent from "../MenuComponent";
import DishDetailComponent from "../DishDetailComponent";
import HomeComponent from "../HomeComponent";
/**
* #author BadalSherpa
* #function HomeNavigation
**/
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const HomeNavigation = (props) => {
return (
<Stack.Navigator initialRouteName='Home'>
<Stack.Screen name='Home' component={HomeComponent} />
<Stack.Screen name='Menu' component={MenuComponent} />
<Stack.Screen name='Dish-Detail' component={DishDetailComponent} />
</Stack.Navigator>
);
};
const MenuNavigation = (props) => {
return (
<Stack.Navigator initialRouteName='Home'>
<Stack.Screen name='Menu' component={MenuComponent} />
</Stack.Navigator>
);
};
const DrawerNavigation = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name='Home' component={HomeNavigation} /> //Here is where we are combining Stack Navigator to Drawer Navigator
<Drawer.Screen name='Menu' component={MenuNavigation} />
</Drawer.Navigator>
);
};
export default DrawerNavigation;
Then you can simple return this inside NavigationContainer which will have both Stack and Drawer Navigator working together.
<NavigationContainer>
<HomeNavigation />
</NavigationContainer>
This is how I use them
const HomeStackNavigator = StackNavigator(
{
Home: {
screen: HomeScreen,
},
Chat: {
screen: ChatScreen,
},
},
{
initialRouteName: 'Home',
headerMode: 'screen',
},
);
const MainDrawerNavigator = DrawerNavigator(
{
Home: {
screen: HomeStackNavigator,
},
},
{
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
contentComponent: SlideMenu,
navigationOptions: {
drawerLockMode: 'locked-closed',
},
},
);
same issue with me, Then i just change my emulator and update the version and it worked 100%.
This is a slightly different take where the drawer navigator controls a stack navigator. Each selection in the drawer will push a child stack element so there is a one-to-one match between the drawer and stack. This is more typical behavior in my experience. All but the home have a title with back navigation indicator.
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';
import {
CompositeNavigationProp,
NavigationContainer,
} from '#react-navigation/native';
import {
createStackNavigator,
StackNavigationProp,
} from '#react-navigation/stack';
import HomeScreen from './HomeScreen';
import SettingsScreen from './SettingsScreen';
import {
createDrawerNavigator,
DrawerContentComponentProps,
DrawerContentOptions,
DrawerContentScrollView,
DrawerItem,
DrawerNavigationProp,
} from '#react-navigation/drawer';
type NoProps = Record<string, object>;
export type ScreenNavigationProps = CompositeNavigationProp<
StackNavigationProp<NoProps>,
DrawerNavigationProp<NoProps>
>;
export type DrawerProps = DrawerContentComponentProps<DrawerContentOptions>;
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator(); // https://reactnavigation.org/docs/stack-navigator/
/**
* Render the content of the drawer. When an item is selected
* it closes the drawer and pushes an element on the stack nav.
* #param props
*/
function CustomDrawerContent(props: DrawerProps) {
const navigation = (props.navigation as unknown) as ScreenNavigationProps;
const openScreen = (name: string) => () => {
navigation.navigate('Home', {screen: name});
navigation.closeDrawer();
};
return (
<DrawerContentScrollView {...props}>
{/* <DrawerItemList {...props} /> */}
<DrawerItem label="Home" onPress={openScreen('Home')} />
<DrawerItem label="Settings" onPress={openScreen('Settings')} />
</DrawerContentScrollView>
);
}
/**
* Render the Home Stack Navigator.
*/
function HomeStack() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={HomeScreen}
options={{headerShown: false}}
/>
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}
/**
* Render the Home Drawer with a custom drawerContent.
*/
function HomeDrawer() {
return (
<Drawer.Navigator
initialRouteName="Home"
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Home" component={HomeStack} />
</Drawer.Navigator>
);
}
const App = () => {
return (
<SafeAreaView style={styles.app}>
<NavigationContainer>
<HomeDrawer />
</NavigationContainer>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
app: {flex: 1},
});
export default App;
The HomeScreen can provide a menu to open the drawer:
const navigation = useNavigation<ScreenNavigationProps>();
const openDrawer = () => {
navigation.openDrawer();
};
Related
I created this homeStack.js file that contains the routes. I want to use a custom background but Navigator override it and I can't seem to fix that.
This is homeStack.js
import { createStackNavigator } from "react-navigation-stack"
import { createAppContainer } from "react-navigation"
import Home from '../components/Home'
import Detail from '../components/Detail'
const screens = {
Home: {
screen: Home,
},
Detail: {
screen: Detail
},
}
const HomeStack = createStackNavigator(screens, {
defaultNavigationOptions: {
headerShown: false
},
});
export default createAppContainer(HomeStack);
This is app.js where I try to set up my background
import { StyleSheet,View,ImageBackground} from 'react-native';
import Navigator from './routes/homeStack'
export default function App() {
// const image = { uri: "./assets/background.jpg" };
const image = require( "./assets/background.jpg");
return (
<View style={styles.container}>
<ImageBackground style={{height:"100%"}} source={image}>
<Navigator />
</ImageBackground>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
});
I want to disable the navigator background so I can use a custom one. I was unable to turn it off.
Use this approach :
const Stack = createNativeStackNavigator();
const StackNavigator = () => {
return (
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName="Home">
<Stack.Screen name="Home" component={Homescreen} />
</Stack.Navigator>
);
};
I am trying to add a drawer navigation to my Home screen how can i do that? Here's my code.
class Navigation extends React.Component {
render() {
return (
<NavigationContainer>
<StatusBar barStyle="light-content" />
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} options={{ title: this.state.name, }} />
<Stack.Screen name="DrawerScreen" options={{ title: 'DrawerScreen' }} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
How can I get use DrawerScreen in my Navigation class? I tried THAT^ but it gives me error saying couldn't find a component for DrawerScreen.
function DrawerScreen() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} />
</Drawer.Navigator>
</NavigationContainer>
);
}
You can do something like this:
import React from 'react';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { createDrawerNavigator, DrawerItems } from 'react-navigation-drawer';
import { View, Text, StyleSheet,Button, SafeAreaView, ScrollView, Image } from "react-native";
import Load from './components/Load';
import Home from './components/Homescreen'
import SignIn from './components/SignIn'
import SignUp from './components/SignOut'
const MainDrawer = createDrawerNavigator({
SignUp:SignUp,
},
);
const App = createStackNavigator({
Load: {
screen: Load,
navigationOptions: {
headerShown:false
},
},
Home: {
screen: Home,
navigationOptions: {
headerShown:false,
},
},
SignIn: {
screen: SignIn,
navigationOptions: {
headerShown:false,
},
},
SignUp: {
screen: MainDrawer,
navigationOptions: {
headerShown:false,
},
},
});
export default createAppContainer(App);
Hope this helps!
With react-navigation 4, I was able to import and use switchNavigator from "react-navigation" package.
import {
createAppContainer,
createSwitchNavigator,
createStackNavigator
} from "react-navigation";
import MainTabNavigator from "./MainTabNavigator";
import LoginScreen from "../screens/LoginScreen";
import AuthLoadingScreen from "../screens/AuthLoadingScreen";
export default createAppContainer(
createSwitchNavigator(
{
App: MainTabNavigator,
Auth: AuthLoadingScreen,
Login: createStackNavigator({ Login: LoginScreen })
},
{
initialRouteName: "Auth"
}
)
);
With react-navigation 5, I don't see the createSwitchNavigator in the package anymore. The documentation isn't helpful either. Is the use now not recommended? My use case is to show login screen before user is logged in and switch to the app after user logs in. React-navigation has given an example of authentication flow but is it possible to use switchNavigator - which seems much simpler.
The switchNavigator was removed because you can do the exact same stuff now with the help of rendering components conditionally.
import React from 'react';
import {useSelector} from "react-redux";
import {NavigationContainer} from "#react-navigation/native";
import { AuthNavigator, MyCustomNavigator } from "./MyCustomNavigator";
const AppNavigator = props => {
const isAuth = useSelector(state => !!state.auth.access_token);
return (
<NavigationContainer>
{ isAuth && <MyCustomNavigator/>}
{ !isAuth && <AuthNavigator/>}
</NavigationContainer>
);
};
export default AppNavigator;
The lines inside the NavigationContainer fully replace the old switch navigator.
I had also used SwitchNavigator of Navigator 4 then after migrating other pages to Navigator 5, i tried to move authentication part to Navigator 5. I could not achieve SwitchNavigator functionality using Navigator 5. Then decided to use "Compatibility layer" provided in Navigation API 5. https://reactnavigation.org/docs/5.x/compatibility
Hope below code will useful for you.
import { createStackNavigator } from '#react-navigation/stack'
import { NavigationContainer } from '#react-navigation/native';
import { createSwitchNavigator } from "#react-navigation/compat";
import { createCompatNavigatorFactory } from '#react-navigation/compat'
const AppStack = createCompatNavigatorFactory(createStackNavigator)(
{ screen: Home },
{headerMode:'none'}
);
const AuthStack = createCompatNavigatorFactory(createStackNavigator)({ screen:Login });
const SwitchNavigator= createSwitchNavigator(
{
Starter: AuthValidation,
App: AppStack,
Auth: AuthStack
},
{
initialRouteName:'Starter'
}
);
export default function App (){
return(
<NavigationContainer>
<SwitchNavigator/>
</NavigationContainer>
);
}
Here AuthValidation validate for token and depending on value it navigate to "Login" or "Home" Page
_checkAuthetication = async() =>{
const isUserAuthenticated= await AsyncStorage.getItem("isAuthenticated");
this.props.navigation.navigate(isUserAuthenticated ? 'App':'Auth');
}
Hey there is no switch navigator in react navigation 5, however you can do this or something on the same lines:
import React, { useEffect } from 'react'
import { StyleSheet, Text, View, ActivityIndicator } from 'react-native'
import { NavigationContainer } from "#react-navigation/native";
import BottomTabsNavigator from './BottomTabsNavigator'
import AccountNavigator from './AccountNavigator'
import firebase from '../api/config'
const SwitchNavigator = ({navigation}) => {
useEffect(() => {
firebase.auth().onAuthStateChanged(user => {
navigation.navigate(user ? "BottomTabsNavigator" : "AccountNavigator")
})
}, [])
return (
<View style={styles.container}>
<Text>Loading...</Text>
<ActivityIndicator size="large" color="#e9446a"></ActivityIndicator>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
export default SwitchNavigator
and then a Stack Navigator :
import React from 'react'
import { createStackNavigator } from '#react-navigation/stack'
import BottomTabsNavigator from './BottomTabsNavigator'
import AccountNavigator from './AccountNavigator'
import SwitchNavigator from './SwitchNavigator'
import { NavigationContainer } from "#react-navigation/native";
const StackApp = createStackNavigator()
export default function Stack() {
return (
<NavigationContainer>
<StackApp.Navigator initialRouteName='Loading' headerMode='none'>
<StackApp.Screen name='Loading' component={SwitchNavigator} />
<StackApp.Screen name='AccountNavigator' component={AccountNavigator}/>
<StackApp.Screen name='BottomTabsNavigator' component={BottomTabsNavigator}/>
</StackApp.Navigator>
</NavigationContainer>
)
}
and then import the Stack navigator into your app.js file like this:
export default App = () => ( <Stack /> )
This is w.r.t to above query
[Then how could we later navigate from a "LoginScreen" (inside
AuthNavigator ) to "HomeScreen" (inside MyCustomNavigator )? – TalESid
Apr 7 at 8:33 ]
const AuthNavigator = () => {
return(
<AuthStack.Navigator>
<Stack.Screen
name="Login"
component={Login}
options={{ headerShown: false }}
/>
<Stack.Screen
name="SignUp"
component={SignUp}
options={{ headerShown: false }}
/>
</AuthStack.Navigator>
);
}
const MyCustomNavigator = () => {
return(
<AppStack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Stack.Screen
name="ListScreen"
component={ListScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Settings"
component={Settings}
options={{ headerShown: false }}
/>
</AppStack.Navigator>
);
}
const AppNavigator = (props) => {
const isAuth = useSelector((state) => !!state.auth.access_token);
return (
<NavigationContainer>
{isAuth && <MyCustomNavigator />}
{!isAuth && <AuthNavigator />}
</NavigationContainer>
);
};
export default AppNavigator;
There isnt a switch navigator in react-navigation v5 or v6. however, i found switch very easy, and i find stack very difficult to use, so i continue to use react-navigation v4.2.0 or 4.4.1, so i can continue using switch
I'm trying to implement a drawer navigation alongside a tab navigation, but I can't seem to wrap my head around how that would be achieved.
The tab would have 5 items, and should be present on all screens. The 5th tab should open a drawer with more menu items.
Clicking on any of the drawer's menu items should of course show those specific screens, but the tab navigation should be still be present.
In the code below the bottom tab bar (which could be replaced by a top tab navigator) is always present.
The last tab contains the the drawer. It doesn't open by default, but this can be achieved by a this.props.navigation.openDrawer() request.
import React from 'react';
import { View, Text } from 'react-native';
import { createBottomTabNavigator, createDrawerNavigator } from 'react-navigation';
const buildScreen = name => {
class Screen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>{name}</Text>
</View>
);
}
}
return Screen;
}
const DrawerScreen = createDrawerNavigator(
{
Child1: buildScreen("DrawerChild 1"),
Child2: buildScreen("DrawerChild 2"),
},
{
// optional drawer options
// cfr. https://reactnavigation.org/docs/en/drawer-based-navigation.html
}
);
export default createBottomTabNavigator({
Tab1: buildScreen("Tab1"),
Tab2: buildScreen("Tab2"),
Tab3: buildScreen("Tab3"),
Tab4: buildScreen("Tab4"),
DrawerScreen,
});
I know this is an old question, but for people still looking for an answer, this is how I implemented mine.
The Drawer Navigation has to be your main navigation. Your tab navigation is nested inside it.
import React from 'react';
import { createDrawerNavigator } from '#react-navigation/drawer';
import AppNavigator from './AppNavigator';
const Drawer = createDrawerNavigator();
function DrawerNavigation() {
return (
<Drawer.Navigator>
<Drawer.Screen name='Home' component={TabNavigation} />
</Drawer.Navigator>
);
}
export default DrawerNavigation;
In your Tab Navigation, the tab which you choose to show your Drawer Navigation (in your case the fifth tab) would have a listener prop which fires a function on tabPress, toggling the drawer navigation
import React from 'react';
import { Text } from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
const Home = () => (
<Text> Hello Home</Text>
);
const Menu = () => {
return null;
};
function TabNavigation(props) {
return (
<Tab.Navigator>
<Tab.Screen
name='Home'
component={Home}
/>
<Tab.Screen
name='Menu'
component={Menu}
listeners={({ navigation }) => ({
tabPress: e => {
e.preventDefault();
navigation.toggleDrawer();
},
})}
/>
</Tab.Navigator>
);
}
export default TabNavigation;
You can create a stackNavigator with two screens and a materialTabNavigator inside:
const SomeStack= createStackNavigator({
Start: StartStack,
HomeScreenTab,
}
and then:
HomeScreenTab: {
screen: HomeScreenTabTab
}
with:
export default createMaterialTopTabNavigator(
{
Home: {
screen: HomeStack,
navigationOptions: {
tabBarAccessibilityLabel: 'Tela Inicial do APP',
tabBarLabel: ({ tintColor }) => <LabelTitle tintColor={tintColor}
label="Start" />,
tabBarIcon: ({ tintColor }) => (
<View style={styles.containerIcon}>
<FontAwesome color={tintColor} name="home" size{icons.iconMd}
light />
</View>
),
},
},
...SomeOtherTabs
}
You put the content of your screens on the screen property and so on.
I have created a custom tab navigator using createMaterialTopTabNavigator but inside one of the tabs I would like to create a StackNavigator. Is this possible?
I have found lots of examples of Tabs nested inside a Stack or Drawer but not an example of a Stack inside a Tab!
In essence I want to have a few buttons on one of the Tab Screens that navigate to some other screens but I don't want to navigate out of the Tab. (the initial Tab is always visible/selected)- just that you can click on a button and go to another screen and then back.
TabNavigator:
- Settings Screen (Tab 1)
-About Us (Button when clicked opens up the About Us Screen)
-Account Settings (Button when clicked opens up the About Us Screen)
-Contact Us (Button when clicked opens up the About Us Screen)
- Search Screen (Tab 2)
- Profile Screen (Tab 3)
Any suggestions on if they is possible would be greatly appreciated! :)
Yes you can do that
You can nest StackNavigator inside TabNavigator by doing something similar to this -
import { TabNavigator, StackNavigator } from 'react-navigation'
export const TabNavigator = TabNavigator({
SettingsScreenStack: { screen: SettingsScreenStack },
SearchScreen: { screen: SearchScreen },
ProfileScreen: { screen: ProfileScreen },
}, {
order: ['SettingsScreenStack', 'SearchScreen', 'ProfileScreen'],
initialRouteName: 'SettingsScreenStack',
});
export const SettingsScreenStack = StackNavigator({
AboutUsScreen: { screen: AboutUsScreen },
AccountSettingsScreen: { screen: AccountSettingsScreen },
ContactUsScreen: { screen: ContactUsScreen },
}, {
initialRoute: 'AboutUsScreen',
})
...
Hope it helped.
Yes you can nest StackNavigator inside TabNavigator
Visit:- Stack Navigator for each Tab
import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
function DetailsScreen() {
return (
/* content */
);
}
function HomeScreen({ navigation }) {
return (
/* content */
);
}
function SettingsScreen({ navigation }) {
return (
/* content */
);
}
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
);
}
const SettingsStack = createStackNavigator();
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}