Stack Navigator not showing the screens - react-native

So I've been trying to get the stack navigator to work. According to the console.log('Main') I do actually enter the main screen. Which is what I want. However, the screen just gives me a blank screen with only the header showing. I have no idea what the issue is. I thought it could be with the styling but I've deleted and changed it and nothing seems to be working as well. How I have been navigating was simply doing < ScreenName />. But that won't work because I'm trying to navigate around with buttons as well.
Screenshot of login
Main
App.js
renderComponent() {
if (this.state.loggedIn) {
return (
<Container />
)
} else {
return (
<LoginForm />
)
}
}
render() {
return (
<View>
<Header title='InTouch' />
{this.renderComponent()}
</View>
);
}
}
Screen Container
import React, { Component } from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import { View, Button } from 'react-native';
import Main from './src/components/Main'
import Upload from './src/components/Upload'
const NavigationStack = createStackNavigator({
Main: {screen: Main },
Upload: {screen: Upload},
},{
navigationOptions: {
gesturesEnabled:false
}
})
const Container = createAppContainer(NavigationStack);
export default Container;
Main.js
export default class Main extends Component<Props> {
state = { currentUser: null}
componentDidMount() {
const { currentUser } = firebase.auth()
this.setState({ currentUser })
}
render() {
console.log("Main")
const { currentUser } = this.state
return (
<View>
<Text>Hello</Text>
<Button title = "Go to upload story" onPress = {() => this.props.navigation.navigate('Upload')} />
<Button
title="Sign out"
onPress={() => firebase.auth().signOut()} />
</View>
);
I just want the Main to show up.

Login screen should be under the stack navigation, and after logging in you can navigate to other screen
try doing it like this
const NavigationStack = createStackNavigator({
Login: {screen: Login }
Main: {screen: Main },
Upload: {screen: Upload},
},{
navigationOptions: {
gesturesEnabled:false
}
})
alternatively you can create separate navigation for login and other screens using switch
const HomeNavigation = createStackNavigator({
Main: {screen: Main },
Upload: {screen: Upload},
},{
navigationOptions: {
gesturesEnabled:false
}
})
const RootNavigation = createSwitchNavigator({
Login: {screen: Login }
Home: {screen: HomeNavigation }
});
and in App.js do
render() {
return (
<RootNavigation/>
);
}

Related

Why is 'this.props.navigation' unavailable to screen component?

I have a drawer navigator that has a stack navigator nested inside it as one of the screen options. I have no issues navigating to any screens in the drawer, but when I try to navigate to another screen in the stack navigator, I dont have access to this.props.navigation. Im confused because the screen is declared in my navigator setup.
AppNavigator:
// all imports
const InboxStack = createStackNavigator(
{
Inbox: {
screen: HomeScreen
},
Conversation: {
screen: ConversationScreen
}
},
{
headerMode: "none",
initialRouteName: "Inbox"
}
);
const MainNavigator = createDrawerNavigator(
{
Inbox: InboxStack,
Second: { screen: SecondScreen },
Third: { screen: ThirdScreen }
},
{
drawerPosition: "left",
initialRouteName: "Inbox",
navigationOptions: ({ navigation }) => ({
title: "Drawer Navigator Header",
headerTitleStyle: {
color: "blue"
},
headerLeft: <Text onPress={() => navigation.toggleDrawer()}>Menu</Text>
})
}
);
const WrapperStackNavigator = createStackNavigator({
drawerNav: MainNavigator
});
const AppContainer = createAppContainer(
createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: WrapperStackNavigator,
Login: LoginScreen,
Register: RegisterScreen
},
{
initialRouteName: "AuthLoading"
}
)
);
export default AppContainer;
utilization of navigation prop in ConversationScreen:
import React from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { loadConversation } from "../actions";
import MessagesList from "../components/MessagesList.js";
class ConversationScreen extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.loadConversation();
}
loadConversation() {
this.props.loadConversation(
this.props.navigation.state.params.convoId // this works!
this.props.navigation.getParams("convoId") // this does not :(
);
}
render() {
return (
<View
style={{
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<Text>Conversation screen</Text>
<MessagesList messages={this.props.messages} />
</View>
);
}
}
const mapStateToProps = ({ conversation, auth }) => {
const { messages } = conversation;
const { user } = auth;
return { messages, user };
};
const mapDispatchToProps = {
loadConversation
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ConversationScreen);
The issue exists with ConversationScreen, I dont have access to the navigation prop, but docs say if its declared in the navigator it should be be passed the navigation prop. Every call using this.props.navigation errors with ... is not a function, ... is undefined
... being this.props.navigation.navigate, this.props.navigation.getParams, etc
After checking the props object through alert(this.props) I verified I had access to the navigation object, even though it appeared to be undefined, ultimately using
componentDidMount() {
loadConversation() {
this.props.loadConversation(
this.props.navigation.state.params.convoId
);
}
}
This got me where I needed to be. although it would have been nice to just use this.props.navigation.getParams()

How to route my login screen in react native?

I want to add a login screen right after my splash screen, and then go to my home screen.
const LoginStack = createStackNavigator({
Login: LoginScreen,
Home: HomeStack,
});
The problem is that my LoginStack is never used even if I call the home screen in my login screen :
<Button onPress = {this.onPressHome}/>
onPressHome = () => {
this.props.navigation.navigate('Home');
};
My App.js
render() {
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
I'm assuming that you're using React Navigation for the routing. You can pass a 2nd argument to the createStackNavigator which is the config for the Stack.
if you pass an object to the stack you can define which screen you want. So your code would look like:
const LoginStack = createStackNavigator({
Login: LoginScreen,
Home: HomeStack,
},
{
initialRouteName: 'Login',
});
And then if you use the button as you're using now it should work just fine.
So in your case you need to change your App.js to look something like this:
export default App extends Component {
componentDidMount = () => {
this.setState({
isLoadingComplete: true
})
}
render() {
// This is the loading screen?
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
) else {
return <LoginStack />
}
Once your LoadingIsComplete becomes true it would render the LoginStack

Using Tab and Stack Navigator Together

I am building an App on React-Native for which I am using React-Navigation
Now, Inside that i am using Stack-Navigation and TabNavigator (updated it DrawerNavigator)
import {
createStackNavigator,
TabNavigator,
DrawerNavigator
} from 'react-navigation';
import CoinCapCharts from "./src/container/CoinCapCharts.js"
import CoinCap from './src/container/CoinCap.js';
//THis is being Exported to App.js
export const Tab = TabNavigator({
TabA: {
screen: CoinCap
},
TabB: {
screen: CoinCap
}
}, {
order: ['TabA', 'TabB'],
animationEnabled: true,
})
export const MyScreen = createStackNavigator({
Home: {
screen: CoinCap
},
CoinCapCharts: {
screen: CoinCapCharts
}
},{
initialRouteName: 'Home',
headerMode: 'none'
});
export const Drawer = DrawerNavigator({
Tabs: { screen: Tab },
Stack: { screen: MyScreen },
})
I am importing this in my App.js where I am doing something like this
import React from 'react';
import {
Drawer
}from './Screen.js';
import {
View
} from 'react-native';
export default class App extends React.Component {
render() {
return (
<View>
<Drawer/>
<Tab/>
</View>
);
}
}
Now, This is indeed showing Tab the first time I run my app but after I navigate to different screen and return back, It doesn't appear to be showing that Tab again
[Question:] What could I be doing wrong and How can I fix it?
Try to define one within the other.
Something like:
const Tab = TabNavigator({
TabA: {
screen: Home
},
TabB: {
screen: Home
}
}, {
order: ['TabA', 'TabB'],
animationEnabled: true,
})
export const MyStack = createStackNavigator({
Home: {
screen: Home
},
CoinCapCharts: {
screen: CoinCapCharts
},
Tab: {
screen: Tab
},
},{
initialRouteName: 'Home',
headerMode: 'none'
});
Now, render MyStack (not sure that Screen is the best name :)
export default class App extends React.Component {
render() {
return (
<View>
<MyStack />
</View>
);
}
}

Replace old StackNavigator with a new one, React Native

I am trying to replace an StackNavigator that should not be used when the user has gone passed the "LogIn" stage. But i can't figure out how to do this, I have tried the reset function but can't get that to work as wanted.
How do I replace an old StackNavigator with a new and use that one? As shown in the example below the system starts with one stack and that stack should not be used after the button has been pressed.
the index code as an example:
import React, { Component } from 'react';
import { AppRegistry, Button, StyleSheet, Text, View } from 'react-native';
import { NavigationActions, StackNavigator } from 'react-navigation';
import App from './App';
class StackNavigatorStuff extends Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
return (
<View style={styles.container}>
<Text>
Welcome to this app
</Text>
<Text style={styles.instructions}>
Some login functions to become
</Text>
<Button title = 'Temp Login Function' onPress={() => /*Here should the stack be replaced with App.MainStackNav*/})}/>
</View>
);
}
}
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({routeName: 'Home'})
]
});
const StackNavigatorLab = StackNavigator({
Home: { screen: StackNavigatorStuff },
//More to be
});
AppRegistry.registerComponent('StackNavigatorLab', () => StackNavigatorLab);
And the App.MainStackNav
const StackNavigatorLab = StackNavigator({
Home: { screen: MainScreenNavigator },
Chat: { screen: ChatNavigator },
NavigationList: { screen: MyNotificationsScreen },
});
Navigation can only happen within a defined router, so you should have a navigator wrapping the screens you want to switch between.
In you index file's StackNavigatorLab, add App.MainStackNav to it as a route. i.e.
const StackNavigatorLab = StackNavigator({
Home: { screen: StackNavigatorStuff },
Main: { screen: App.MainStackNav },
...
});
And then your reset action would look like
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Main' })
]
});
Use navigation.dispatch to dispatch this reset action after successful login.
If you want to separate two sets of StackNavigation screens, you can have an overall StackNavigator as a root that just wraps the Login set of screens and the Main set of screen.

Q: ReactNative StackNavigator inside DrawerNavigator

is there any good no bugs example with StackNavigator inside DrawerNavigator?
As in my example when the drawer is open the top Navigation title is hidden and I can't open the drawer(with slide) when I am inside the NewScreen page.
So I want to open the drawer over the title and from any page.
Thanks
http://image.prntscr.com/image/eb4d869acbcf4d22a08159b072aae930.png
Here is the code
import React, { Component } from 'react';
import {
AppRegistry,
Button,
Platform,
ScrollView,
StyleSheet,
TouchableHighlight,
Text,
} from 'react-native';
import {
DrawerNavigator,StackNavigator
} from 'react-navigation';
import FontAwesome from "react-native-vector-icons/FontAwesome";
class ScreenHome extends Component{
static navigationOptions = {
title: 'ScreenHome',
};
render() {
const { navigate } = this.props.navigation;
return (
<Button
title="Go to Jane's profile"
onPress={() => navigate('New', { name: 'Jane' })}
/>
);
}
}
class NewScreen extends Component{
static navigationOptions = {
title: 'New screen',
};
render() {
const { navigate } = this.props.navigation;
return (
<Text>Some new screen</Text>
);
}
}
class ScreenRegister extends Component{
static navigationOptions = {
title: 'ScreenRegister',
};
render(){
return <Text>ScreenRegister</Text>
}
}
const MainScreenNavigator = DrawerNavigator({
Recent: {
screen: ScreenHome
},
All: {
screen: ScreenRegister
},
});
export default SimpleApp = StackNavigator({
Home: {
screen: MainScreenNavigator
},
Chat: {
screen: ScreenHome
},
New: {
screen: NewScreen
}
});
AppRegistry.registerComponent('naviTest', () => SimpleApp);
If I got your questions correctly, you want:
1) To have access to the drawer from any page
2) Your drawer to cover the title bar when open.
To achieve Number 1
There are two ways you can do it and they are:
a) Add a button/Icon that triggers the drawer on click. When you use this solution, you will still not have the slide from left functionality as this is controlled explicitly by the DrawerNavigator
b) Add NewScreen to your Drawer since you want to have access to the entire drawer when you are within the screen
To achieve Number 2
This is a very common issue when nesting DrawerNavigator within StackNavigator. To resolve this, modify StackNavigator thus
export default SimpleApp = StackNavigator({
Home: {
screen: MainScreenNavigator
},
Chat: {
screen: ScreenHome
},
New: {
screen: NewScreen
}
}, {
navigationOptions: { header: false }
});