react native - how to use stackNavigator and DrawerNavigator together - reactjs

I am trying to use react native DrawerNavigator and StackNavigator together but for some reason I can't make it work.
Below is my code:
import {DrawerNavigator,StackNavigator, } from 'react-navigation'
class App extends Component {
render(){
return(
<View style={{flex:1,backgroundColor:'transparent'}}>
<AppStackNavigator/>
<AppDrawerNavigator/>
</View>
)
}
}
const AppDrawerNavigator = DrawerNavigator({
Home:HomeScreen,
Price:PriceScreen,
Info:InfoScreen,
Login:LoginScreen
})
const AppStackNavigator = StackNavigator({
Home:HomeScreen,
Price:PriceScreen,
Info:InfoScreen,
Login:LoginScreen
})
export default App
When I run this code my app screen is split into half, top have shows stackNavigator screen and the bottom half shows DrawerNavigator screen.
Is there a way I can make these two work together?
Also, what is the difference between stackNavigator and createStack Navigator? I don't see the diffence when I run these.

You need to nest the Navigators to get the result you are asking for.
For example if you want a stack navigation inside one of the screens in your drawer navigation you can do this:
import {DrawerNavigator, StackNavigator} from 'react-navigation'
class App extends Component {
render() {
return (
<View style={{ flex: 1, backgroundColor: 'transparent' }}>
<AppDrawerNavigator />
</View>
)
}
}
const AppStackNavigator = StackNavigator({
Home: HomeScreen,
Price: PriceScreen,
Info: InfoScreen,
Login: LoginScreen
})
const AppDrawerNavigator = DrawerNavigator({
Home: AppStackNavigator,
// Price: PriceScreen,
// Info: InfoScreen,
// Login: LoginScreen
})
export default App
The important part is
const AppDrawerNavigator = DrawerNavigator({
Home: AppStackNavigator, <--- This
// Price: PriceScreen,
// Info: InfoScreen,
// Login: LoginScreen
})
Now the "Home" Screen in your Drawer Navigation has the ability to use the stack navigation. You can do this for the others screens as well.

Related

Using React Navigation for a Navigator inside a Screen?

In my react native app, I have a stack navigator as so:
const AppStack = createStackNavigator(
{
Tabs: AppTabs,
Account: AccountScreen,
Profile: ProfileScreen,
Post: PostScreen,
},
);
The ProfileScreen contains some header content and another TabNavigator, in a layout similar to when you click on a channel in Youtube:
const ProfileTabs = createMaterialTopTabNavigator(
{
Home: ProfileHome,
Posts: ProfileMade,
},
);
const ProfileNav = createAppContainer(ProfileTabs);
class ProfileScreen extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
<View>Some header content</View>
<ProfileNav />
</View>
);
}
}
My problem is that I am unable to navigate from inside the ProfileTabs navigator to a screen in the original stacknavigator. E.g. if a user clicks on a post in the ProfileMade screen, I want to navigate them to the PostScreen.
Please can someone tell me what should be changed? Thanks
You can navigate to another stack sending the name of stack on the .navigate() method:
navigation.navigate('StackName', {
screen: 'YourScreenName'
});

Problem to return component from StackNavigator in react-native. Get a blank screen but cosole.log is OK

What I want to do is wrapp on the very top of my app a switch navigator named MainNavigator which redirect to a LoadingScreen who determine if user is Logged or no and navigate to AuthNavigator or AppNavigator.
AuthNavigator himself is a stackNavigator who display screens 'LoginScreen' or 'SignUpScreen'.
AppNavigator is a DrawerNavigator with multiple screens (Profile, Home...).
The problem I encouter is that the return method seems to work, because I can see the logs in my console from the 'LoginScreen' component but on the screen, the only return is a white screen.. When I call directly my 'LoginScreen' component from the LoadingScreen component by using :
_bootstrapAsync = async () => {
const userToken = await AsyncStorage.getItem('userToken');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away. switched to develop the app
this.props.navigation.navigate(userToken ? 'App' : 'LoginScreen');
};
I had the LoginScreen component rendered on my device.
I know the problem come from my AuthNavigator and AppNavigator because I can return screens components from AuthLoading or MainNavigator
Here some code :
* Main Navigator: entry point of the app
* Redirect to AuthLoadingScreen by default,
* if user is signed (AsyncStorage) or successly signIn
* redirect to AppNavigator else if user isn't SignIn
* go to AuthNavigator
import { createAppContainer, createSwitchNavigator } from 'react-
navigation';
import AuthNavigator from './auth/AuthNavigator'
import AppNavigator from './app/AppNavigator'
import AuthLoadingScreen from '../screens/auth/AuthLoadingScreen'
export default createAppContainer(createSwitchNavigator(
{
// You could add another route here for authentication.
// Read more at https://reactnavigation.org/docs/en/auth-flow.html
AuthLoading: AuthLoadingScreen,
App: AppNavigator,
Auth: AuthNavigator,
},
{
initialRouteName: 'AuthLoading',
}
));
AuthLoading :
import React from 'react';
import {
ActivityIndicator,
AsyncStorage,
StatusBar,
StyleSheet,
View,
Text
} from 'react-native';
export default class AuthLoadingScreen extends React.Component {
constructor(props) {
super(props);
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await AsyncStorage.getItem('userToken');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away. switched to develop the app
this.props.navigation.navigate(userToken ? 'App' : 'Auth');
};
// Render any loading content that you like here
render() {
return (
<View>
<Text>Loading</Text>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}
AuthNavigator:
import { createStackNavigator } from 'react-navigation';
import LoginScreen from '../../screens/auth/LoginScreen';
import SignUpScreen from '../../screens/auth/SignUpScreen';
export default createStackNavigator({
Login : {
screen : LoginScreen
},
SignUp: {
screen : SignUpScreen
}
},
{
initialRouteName: 'Login',
})
LoginScreen:
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
export default class LoginScreen extends Component {
render() {
console.log('LOGIN SCREEN')
return (
<View style={styles.container}>
<Text style={styles.text}>Login</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
text : {
fontSize: 20,
}
});
I can't find the error, but I know it comes from the AuthNavigator and AppNavigator. I can see the 'LOGIN SCREEN' or 'APP SCREEN' if I set the AuthLoading route to render App in my console but nothing on the screen, when I init a new route LoginScreen in my MainNavigator and navigate to that route from the AuthLoading it works, I have a beautiful text displayed on my screen.
I Know it's probably an insignifiant error but I spend hours to fix this by myself and can't find, so if someone can help me it would be nice!
Thanks by advance!
Problem solved... Because at the top of my app in App.js I wrapped my MainNavigator like that
<View>
<StatusBar hidden={true} />
<MainNavigator />
</View>
So I remove the view and statusbar... and it works. 4 days to figure it out... I love it! :')

React Navigation confusion

I started learning React Native, I know how to create TabNavigator or DrawerNavigator but I need access to props.navigation on landing page where I don't have TabNavigation, how I'am supposed to get it.
I tried this:
const App = createStackNavigator({
LandingScreen: { screen: LandingScreen },
Register: { screen: RegisterScreen },
Login: { screen: LoginScreen}});
But still, this.props are empty object.
And what is stackNavigator in plain language, does it just define navigation in order to be able to use navigation ?
In your LandingScreen you can able to get the this.props.navigation. You can show your TabNavigation as your initial route. You can even set Stack Navigation for each Tab. For React Navigation(v2) Documentation https://reactnavigation.org/docs/en/tab-based-navigation.html
Stack Navigation:
Provides a way for your app to transition between screens where each new screen is placed on top of a stack.
//Stack Navigator
const App = createStackNavigator({
Home: { screen: Tabs }, //You can nest your TabNavigator here, Hence the LandingScreen inside your HomeStack will shown as your Initial screen
Register: { screen: RegisterScreen },
Login: { screen: LoginScreen}});
//Sample Tab Navigator
const Tabs = createBottomTabNavigator(
{
Home: HomeStack,
Settings: SettingsStack,
},
{
/* Other configuration remains unchanged */
}
);
const HomeStack = createStackNavigator({
LandingScreen: LandingScreen,
Details: DetailsScreen,
});
const SettingsStack = createStackNavigator({
Settings: SettingsScreen,
Details: DetailsScreen,
});
You can get your navigation Prop by using below
//LandingScreen Component
export default LandingScreen extends Component{
static navigationOptions = ({navigation}) => ({ //you can able to destructure your navigation prop here
headerTitle: 'Langing Page'
})
render(){
return(
//your logic here
)
}
}

Rendering both drawer and tabbed navigation with react navigation

I'm using React Navigation in my react native app, and I'm looking to render both the drawer navigation and tab navigation components simultaneously.
At first, I tried to render both in the root app component, but that threw an error that appears in their documentation here. I then attempted the solution listed below, which produced the following for me:
const TabNavigator = createBottomTabNavigator({
Settings: {
screen: SettingsScreen
}
});
const AppNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen
},
Products: {
screen: ProductsScreen
},
TabNav: TabNavigator
});
export default class App extends React.Component {
render() {
return <AppNavigator />;
}
}
The tab navigation only shows when I select the TabNav link in the drawer navigation. I want it on every screen. I also don't want the TabNav label to show in the drawer navigation.
Am I missing something in the documentation, or is this the intended functionality?
For the first question, move the TabNav to first in the navigator like this
TabNav: TabNavigator,
Home: {
screen: HomeScreen
},
Products: {
screen: ProductsScreen
}
or else you change the initialRouteName to "TabNav"
For the Second question,
If you want the TabNavigation to show inside the HomeScreen and ProductsScreen you need to include TabNavigation in both
or they need to have a parent TabNavigation which contains those. I can add a sample code if you post what the TabNav contains.
And for the Third question,
You can use contentComponent in DrawerNavigator example like this
contentComponent: props => (
<AppDrawerContent {...props} navigation={props.navigation} />
),
Edited:
If you want TabNavigator to show on each one. I think you should change the way you Structure your navigator.
export default class App extends React.Component {
render() {
return < TabNavigator />;
}
}
const TabNavigator = createBottomTabNavigator({
Drawer: {
screen: AppNavigator
}
});
const AppNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen
},
Products: {
screen: ProductsScreen
}
});
or else if you want TabNavigator inside each screen individually then
const AppNavigator = createDrawerNavigator({
HomeNavigator: {
screen: HomeScreenNavigator
},
Products: {
screen: ProductsScreen
}
});
const HomeScreenNavigator = createBottomTabNavigator({
Home: {
screen: HomeScreen
},
Settings: {
screen: SettingsScreen
}
});
export default class App extends React.Component {
render() {
return <AppNavigator />;
}
}
Like wise for Products screen also.
What you have actually done is you included the TabNav as Drawer Screen so it does appear in the Drawer side bar.
Even if this structure doesn't work you need to check on restructuring it. Or you may give a images how you want to show it. May be I could help you with better understanding.

Integrate StackNavigator with TabNavigator

How do I combine StackNavigator and TabNavigator?
My following code works:
index.android.js :
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
import { StackNavigator,TabNavigator } from 'react-navigation';
import TestComp1 from './src/components/TestComp1'
import TestComp2 from './src/components/TestComp2'
import TestComp3 from './src/components/TestComp3'
import TestComp4 from './src/components/TestComp4'
import TestComp5 from './src/components/TestComp5'
export default class myApp extends Component {
render() {
return (
<MyApp />
);
}
}
const MyApp = StackNavigator({
TestComp1: {screen:TestComp1},
TestComp2: {screen:TestComp2}
});
const Tabs = TabNavigator({
TestComp3: {screen:TestComp3},
TestComp4: {screen:TestComp4}
TestComp5: {screen:TestComp5}
});
AppRegistry.registerComponent('myApp', () => myApp);
This works only for StackNavigator. I want to keep the existing navigation and integrate TabNavigation. Now in TestComp1 if I do the following:
TestComp1 :
import { StackNavigator, TabNavigator } from 'react-navigation';
import { FooterTabs } from './routes/FooterTabs';
export default class HomePage extends Component {
static navigationOptions = {
header: null
};
render() {
return(
<View style={styles.container}>
<View style={styles.mainContent}>
<Button
onPress={() => this.props.navigation.navigate('TestComp1', {name: 'Lucy'})}
title="NewPage"
/>
<FooterTabs /> //Page shows all StackNavigator screens if I add this
</View>
</View>
)
}
}
And the FooterTabs:
import { StackNavigator, TabNavigator } from 'react-navigation';
import TestComp3 from '../TestComp3';
import TestComp4 from '../TestComp4';
import TestComp5 from '../TestComp5';
export const FooterTabs = TabNavigator({
Tab1: {
screen: TestComp3
},
Tab2: {
screen: TestComp4
},
Tab3: {
screen: TestComp5
},
})
The FooterTabs is shown but TestComp1 and TestComp2 are also shown everything below one another. How do I fix this? Thanks.
UPDATE 1:
UPDATE 2:
const Tabs = TabNavigator({
TestComp3: {screen:TestComp1},
TestComp4: {
screen:TestComp4,
navigationOptions: ({ navigation }) => ({
title: "TestComp4",
tabBarIcon: ({ tintColor }) => <MaterialIcons name="accessibility" size={20}/>
})
}
UPDATE 3
I added another const for DrawerNavigator and configured it like this:
const Drawer = DrawerNavigator({
First:{
screen: DrawerScreen1
},
Second:{
screen: DrawerScreen2
}
},{
initialRouteName:'First',
drawerPosition: 'left'
});
And included in the app:
const MyApp = StackNavigator({
TestComp1: {screen:TestComp1},
TestComp2: {screen:TestComp2},
Tabs: {
screen: Tabs
},
Drawer: {
screen: Drawer
},
}, {
initialRouteName: "Tabs"
});
I'm calling it :
<Button
onPress={() => this.props.navigation.navigate('DrawerOpen')}
title="Show Drawer"
/>
OnPress of this button the DrawerScreen1 is called but as a component, it does not show as a drawer from the left. What am I missing?
You can try this:
const Tabs = TabNavigator({
TestComp3: {screen:TestComp3},
TestComp4: {screen:TestComp4}
TestComp5: {screen:TestComp5}
});
const MyApp = StackNavigator({
TestComp1: {screen:TestComp1},
TestComp2: {screen:TestComp2},
Tabs: {
screen: Tabs
}
}, {
initialRouteName: "Tabs"
});
and remove <FooterTabs /> from TestComp1
Let's see now. What you need is first a StackNavigator then inside one of the screens of the StackNavigator you need a TabNavigator. Right?
The answer to this would be the following:
For your index.android.js:
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
import TestComp1 from './src/components/TestComp1'
import TestComp2 from './src/components/TestComp2'
// Don't need to export default here since this is the root component
// that is registered with AppRegistry and we don't need to import it anywhere.
class myApp extends Component {
render() {
return (
<MyApp />
);
}
}
// Notice that these two screens will consist the navigation stack.
// Assume, TestComp1 contains our Tabbed layout.
const MyApp = StackNavigator({
TestComp1: { screen:TestComp1 }, // This screen will have tabs.
TestComp2: { screen:TestComp2 }
});
AppRegistry.registerComponent('myApp', () => myApp);
Let's now move on to your TestComp1, which is the screen that has your tabs.
TestComp1:
// ... all imports here.
// This should be your first tab.
class Home extends Component {
static navigationOptions = {
// Label for your tab. Can also place a tab icon here.
tabBarLabel: 'Home',
};
render() {
return(
<View style={styles.container}>
<View style={styles.mainContent}>
// This will change your tab to 'Profile'.
<Button
onPress={() => this.props.navigation.navigate('Profile', {name: 'Lucy'})}
title="NewPage"
/>
</View>
</View>
)
}
}
// This can be your second tab and so on.
class Profile extends Component {
static navigationOptions = {
// Label for your tab.
tabBarLabel: 'Profile',
};
render() {
return (
<Text>This is the profile Tab.<Text>
);
}
}
export default TabNavigator({
Home: {
screen: Home,
},
Profile: {
screen: Profile,
},
}, {
// This will get the tabs to show their labels/icons at the bottom.
tabBarPosition: 'bottom',
animationEnabled: true,
tabBarOptions: {
activeTintColor: '#e91e63',
},
});
So essentially, your TestComp1 has two components (Home and Profile) inside it which are both parts of TabNavigator so they'll act as tabs. (You don't need to worry about a separate footer component as ReactNavigation places that automatically using your component's navigationOptions) We'll be exporting this TabNavigator instance that we'll use as an import to index.android.js and we'll place this import inside our StackNavigator as a screen of the app.
This way you've incorporated Tabs as well as StackNavigator inside your RN app. Also, tabBarPosition: 'bottom' places your tabs at the bottom.
You also no longer to maintain a separate FooterTabs component as you can see.
Read up the docs if you need more clarity or fine-tuning.
Hope I've helped. :)

Resources