I created a basic SplashScreen.tsx that just has some text on it. Then, I created this LoginCreateAccountScreen.tsx, which has a Login button and Create Account button. I want my app to show the SplashScreen.tsx for a few seconds before it automatically navigates to LoginCreateAccountScreen.tsx. Also, pressing the buttons should redirect the user to other screens, but that also does not work. I don't know how to do this and have had a lot of difficulties figuring out exactly how to accomplish this.
I used this React Native Navigation Article as well as This Tutorial to get to where I am right now, along with various StackOverflow posts. But to be honest, I am pretty lost as there is just so much going on with regards to frontend navigation.
I don't understand how AppNavigator.js and App.js (the entry point for my app) work in conjunction to let me be able to navigate to another screen from my current screen. Right now, I can't get any kind of navigation working. I have to manually change the screen by setting it in App.js.
My App.js, which renders the SplashScreen. But won't transition to the LoginCreateAccountScreen.
import React, { Component } from 'react';
import EmojiDict from './screens/EmojiDict';
import SplashScreen from './screens/SplashScreen';
import LoginCreateAccountScreen from './screens/LoginCreateAccountScreen'
export default class App extends Component {
render() {
return <SplashScreen />;
}
}
My AppNavigator.js:
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation";
import MainTabNavigator from "./MainTabNavigator";
import { Platform } from "react-native";
// Importing my screens here.
import LoginCreateAccountScreen from "../screens/LoginCreateAccountScreen";
import CreateAccountScreen from "../screens/CreateAccountScreen";
import LoginScreen from "../screens/Login/LoginScreen";
import SplashScreen from "../screens/SplashScreen";
const MainNavigator = createStackNavigator({
SplashScreen: {screen: SplashScreen},
LoginCreateAccountScreen: {screen: LoginCreateAccountScreen},
LoginScreen: {screen: LoginScreen},
CreateAccountScreen: {screen: CreateAccountScreen},
});
const App = createAppContainer(MainNavigator);
export default App;
My SplashScreen.tsx:
import React, { Component } from 'react';
import { View, Text, StyleSheet, FlatList } from 'react-native';
class SplashScreen extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>
The Good App
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 45,
textAlign: 'center',
fontWeight: 'bold'
}
});
export default SplashScreen;
My LoginCreateAccountScreen.tsx:
import React, { Component } from 'react';
import {
StyleSheet,
Button,
View,
SafeAreaView,
Text,
Alert,
TouchableOpacity
} from 'react-native';
import Constants from 'expo-constants';
function Separator() {
return <View style={styles.separator} />;
}
class CreateAccountOrLogin extends Component {
handleLogInButton = () => {
Alert.alert('Log In pressed')
this.props.navigation.navigate("LoginScreen");
};
handleCreateAccountButton = () => {
Alert.alert('Create Account pressed')
this.props.navigation.navigate("CreateAccountScreen");
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.customButtonBackground}
onPress={() => this.handleLogInButton()}>
<Text style={styles.customButtonText}>Login</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.customButtonBackground}
onPress={() => this.handleCreateAccountButton()}>
<Text style={styles.customButtonText}>Create Account</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
/* Here, style the text of your button */
customButtonText: {
fontSize: 35,
fontWeight: '400',
color: "#fff",
textAlign: 'center'
},
/* Here, style the background of your button */
customButtonBackground: {
backgroundColor: "#007aff",
paddingHorizontal: 30,
paddingVertical: 5,
borderRadius: 30,
width: "70%",
aspectRatio: 5 / 1,
}
});
export default CreateAccountOrLogin;
I get the following error when I press on the Login or Create Account button, which is the same for both:
This is where react navigation is useful. Ill guide you with this. I believe you have installed react navigation as per the docs. Otherwise make sure to download that first. Check this react-navigatoin-doc . Hope it helps.
So let's start with the stack navigator first, So you want to show splashscreen at start and then navigate to loginscreen right. So AppNavigator should look like this :
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation";
import MainTabNavigator from "./MainTabNavigator";
import { Platform } from "react-native";
// Importing my screens here.
import LoginCreateAccountScreen from "../screens/LoginCreateAccountScreen";
import CreateAccountScreen from "../screens/CreateAccountScreen";
import LoginScreen from "../screens/Login/LoginScreen";
import SplashScreen from "../screens/SplashScreen";
const MainNavigator = createStackNavigator({
SplashScreen: {screen: SplashScreen},
LoginCreateAccountScreen: {screen: LoginCreateAccountScreen},
LoginScreen: {screen: LoginScreen},
CreateAccountScreen: {screen: CreateAccountScreen},
},
{ initialRouteName: 'SplashScreen'} // have added this coz you want splashscreen to be first rendered
);
const App = createAppContainer(MainNavigator);
export default App;
So now that your app navigator has been made, now lets switch to splash screen where you want it to be rendered for suppose 3 secs and then navigate it to LoginScreen. So we will redirect to login screen in componentDidMount , lets build that one.
Splashscreen:
import React, { Component } from 'react';
import { View, Text, StyleSheet, FlatList } from 'react-native';
class SplashScreen extends Component {
componentDidMount(){
this.setTimeout(() => {this.props.navigation.navigate("LoginScreen")} , 3000); // im redirecting to login screen after 3 secs of showing splash screen.
}
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>
The Good App
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 45,
textAlign: 'center',
fontWeight: 'bold'
}
});
export default SplashScreen;
And after that , in login screen you can redirect the user from login to any screen by this.props.navigation.navigate("ScreenName") , just make sure you add your screen in the AppNavigator before doing the above code, like first
import ScreenName from "../screens/ScreenName";
const MainNavigator = createStackNavigator({
SplashScreen: {screen: SplashScreen},
LoginCreateAccountScreen: {screen: LoginCreateAccountScreen},
LoginScreen: {screen: LoginScreen},
CreateAccountScreen: {screen: CreateAccountScreen},
ScreenName:{screen:ScreenName}
},
{ initialRouteName: 'SplashScreen'} // have added this coz you want splashscreen to be first rendered
);
then only this.props.navigation.navigate("ScreenName") this would work.
Hope it helps. feel free for doubts
Error message says, "There is no navigation props in your Create Account Login component."
You need to add CreateAccountOrLogin to createStackNavigator, then createStackNavigator pass navigation props to CreateAccountOrLogin.
const MainNavigator = createStackNavigator({
SplashScreen: {screen: SplashScreen},
LoginCreateAccountScreen: {screen: LoginCreateAccountScreen},
LoginScreen: {screen: LoginScreen},
CreateAccountScreen: {screen: CreateAccountScreen},
+ CreateAccountOrLogin
});
Just write below code in CreateAccountOrLogin to know whether props.navigation is exist.
render() {
console.log(this.props)
return(
Related
I am new to react native and I have been trying to create a header and pull out menu using createDrawerNavigator.
When running my code I get the following error.
Error: The component for route 'Home' must be a React component. For example:
import MyScreen from './MyScreen';
Home: MyScreen,
}
You can also use a navigator:
import MyNavigator from './MyNavigator';
Home: MyNavigator,
}
Here is my app.js file:
import React from 'react';
import { Button, View, Text } from 'react-native';
import { createAppContainer } from 'react-navigation';
import MyDrawerNavigator from './components/MyDrawerNavigator';
const MyApp = createAppContainer(MyDrawerNavigator);
export default class App extends React.Component {
render() {
return <MyApp />;
}
}
My HomeScreen.js file
import React from 'react';
import { Text, Button } from 'react-native';
import LogoTitle from './LogoTitle';
class MyHomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <LogoTitle />,
headerLeft: (
<Button
onPress={() => this.props.navigation.navigate('DrawerToggle')}
title={'Menu'}
/>
),
};
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
}
export default MyHomeScreen;
My MyDrawerNavigator.js file
import React from 'react';
import { Button, Platform, Image, View, Text } from 'react-native';
import { createDrawerNavigator } from 'react-navigation-drawer';
import MyHomeScreen from './HomeScreen';
import DetailsScreen from './DetailScreen';
const MyDrawerNavigator = createDrawerNavigator(
{
Home: MyHomeScreen,
Details: DetailsScreen,
}, {
drawerPosition: 'right',
contentOptions: {
activeTintColor: '#000',
},
});
export default MyDrawerNavigator
The are 2 problems here:
1) You are not exporting your MyDrawerNavigator just add:
export default MyDrawerNavigator
to your MyDrawerNavigator.js file
2) You are not exporting your HomeScreen. You'll have to create a separate file for it, like you did with DetailsScreen.
The HomeScreen.js file would look like:
class MyHomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <LogoTitle />,
headerLeft: (
<Button
onPress={() => this.props.navigation.navigate('DrawerToggle')}
title={'Menu'}
/>
),
};
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
}
You NEED to add a render inside of your screens
Am trying to start playing with React Native now. And I come from web development field.
Since start, am trying to organize my folder structure so that it would be easy for me to understand and make modifications later.
Right now the folder structure is as follows:
/screens
HomeScreen.js
ProfileScreen.js
/navigation
MainNavigation.js
App.js
... etc
Am using Expo CLI as this is my first time working on React Native.
/navigation/MainNavigation.js
import React from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import HomeScreen from '../screens/HomeScreen';
import ProfileScreen from '../screens/ProfileScreen';
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Profile: ProfileScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class Navigation extends React.Component {
render() {
return (
<AppContainer />
);
}
}
/screens/HomeScreen.js
import React from 'react';
import { StyleSheet, Text, View, Button, TouchableOpacity } from 'react-native';
export default function HomeScreen() {
return (
<View style={styles.container}>
<TouchableOpacity style={styles.blue_btn} onPress={() => this.props.navigation.navigate('Profile')}>
<Text style={styles.white_text}>Profile</Text>
</TouchableOpacity>
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
HomeScreen.navigationOptions = {
header: null,
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
blue_btn: {
backgroundColor: '#13baa8',
padding: 10,
},
white_text: {
color: 'white',
}
});
/screens/ProfileScreen.js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
export default function ProfileScreen() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
ProfileScreen.navigationOptions = {
title: 'Profile',
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
App.js
import React from 'react';
import Navigation from './navigation/MainNavigation';
export default class App extends React.Component {
render() {
return (
<Navigation />
);
}
}
When I click on the Profile button in the HOME Screen, it is showing this message:
undefined is not an object(evaluating '_this.props.navigation')
Thank you
import React, { Component } from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import ScreenOne from './ScreenOne';
import ScreenTwo from './ScreenTwo';
const NavStack = createStackNavigator({
ScreenOne: {
screen: ScreenOne,
},
ScreenTwo: {
screen: ScreenTwo,
},
});
const App = createAppContainer(NavStack);
export default App;
I have created a MenuButton as well as 2 other pages one of them being the settingScreen, where I have imported the MenuButton within both files and they seem to be working fine. But when I import the setting Screen on the DrawerNavigator file it doesn't recognize MenuButton
Failed to load bundle(http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false) with error:(Unable to resolve module `./Menu/MenuButton` from `/Users/camillebasbous/Project/Menu/SettingScreen.js`: The module `./Menu/MenuButton` could not be found from `/Users/camillebasbous/Project/Menu/SettingScreen.js`. Indeed, none of these files exist:
* `/Users/camillebasbous/Project/Menu/Menu/MenuButton(.native||.ios.js|.native.js|.js|.ios.json|.native.json|.json|.ios.ts|.native.ts|.ts|.ios.tsx|.native.tsx|.tsx)`
* `/Users/camillebasbous/Project/Menu/Menu/MenuButton/index(.native||.ios.js|.native.js|.js|.ios.json|.native.json|.json|.ios.ts|.native.ts|.ts|.ios.tsx|.native.tsx|.tsx)` (null))
__38-[RCTCxxBridge loadSource:onProgress:]_block_invoke.228
RCTCxxBridge.mm:414
___ZL36attemptAsynchronousLoadOfBundleAtURLP5NSURLU13block_pointerFvP18RCTLoadingProgressEU13block_pointerFvP7NSErrorP9RCTSourceE_block_invoke.118
__80-[RCTMultipartDataTask URLSession:streamTask:didBecomeInputStream:outputStream:]_block_invoke
-[RCTMultipartStreamReader emitChunk:headers:callback:done:]
-[RCTMultipartStreamReader readAllPartsWithCompletionCallback:progressCallback:]
-[RCTMultipartDataTask URLSession:streamTask:didBecomeInputStream:outputStream:]
__88-[NSURLSession delegate_streamTask:didBecomeInputStream:outputStream:completionHandler:]_block_invoke
__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__
-[NSBlockOperation main]
-[__NSOperationInternal _start:]
__NSOQSchedule_f
_dispatch_call_block_and_release
_dispatch_client_callout
_dispatch_continuation_pop
_dispatch_async_redirect_invoke
_dispatch_root_queue_drain
_dispatch_worker_thread2
_pthread_wqthread
start_wqthread
I have tried testing ou the other page and after a few tests I realized that the presence of the imported MenuButton within these pages is what is forcing an error Is there a way to import a file that has imported another to be displayed or do I have to import both of them within drawerNavigation and if so how to structure the code. Thanks
Drawer Navigation code:
import * as React from 'react';
import { Text, View, Image, ScrollView, StyleSheet } from 'react-native';
import {
createDrawerNavigator,
createAppContainer,
DrawerItems,
SafeAreaView,
} from 'react-navigation';
import SettingScreen from './Menu/SettingScreen'
class Home extends React.Component {
static navigationOptions = {
title: 'Home',
};
render() {
return (
<View style={styles.container}>
<SettingScreen/>
</View>
);
}
}
const Navigator = createDrawerNavigator(
{
Home,
},
{
//drawerType: 'back',
// drawerPosition: 'right',
// drawerWidth: 200,
drawerBackgroundColor: '#262A2C',
// contentComponent: CustomDrawerContentComponent
}
);
export default createAppContainer(Navigator);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
}
});
SettingScreen code:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import MenuButton from './Menu/MenuButton'
export default class SettingScreen extends React.Component{
render(){
return(
<View style={styles.container}>
<MenuButton/>
<Text style={styles.text}>Settings</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'rgba(215,215,215,1)',
alignItems: 'center',
justifyContent: 'center',
},
text:{
fontSize: 30,
}
});
MenuButton code:
import React from 'react';
import {AppRegistry, StyleSheet, View} from "react-native" ;
import Icon from 'react-native-vector-icons/Ionicons'
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen'
export default class MenuButton extends React.Component {
render() {
return(
<View >
<Icon name= "ios-menu" size={wp('12%')} color='#9B9B9B' style={{position: 'absolute', top: wp('-82.5%'), left: wp('-46%'), }}></Icon>
</View>
)
}
}
AppRegistry.registerComponent('Menu', () => FixedDimensionsBasics);
The path you are using on import is relative to your file. So, as everything is on the same folder, you must correct the import path like that:
On Drawer Navigator code
import SettingScreen from './SettingScreen'
On SettingScreen code
import MenuButton from './MenuButton'
In my React- Native project I have installed the following version of react-navigation:
npm install react-navigation#^1.0.0-beta.11
And then run the command:
npm install
After all these installation I have created a class named WelcomeScreen.js and here is the code given below for that-
WelcomeScreen.js
import React, { Component } from "react";
import {
View,
StyleSheet,
Button
} from "react-native";
class WelcomeScreen extends Component {
static navigationOptions = {
header: 'none'
}
render() {
return (
<View style={styles.container}>
<Button title="Log in" onPress={() => this.props.navigation.navigate('LoginScreen')}/>
<Button title="Sign Up" onPress={() => this.props.navigation.navigate('SignUpScreen')}/>
</View>
)
}
}
export default WelcomeScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
});
After that, I have routed this class in my App.js file. Here is the code given below:
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation'
import WelcomeScreen from './screens/WelcomeScreen'
export default class App extends React.Component {
render() {
return (
<AppStackNavigator/>
);
}
}
const AppStackNavigator = new StackNavigator({
WelcomeScreen: { screen: WelcomeScreen }
})
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Then after running my project, I am keep getting this error:
Invarient violation:Text strings must be rendered within a component
Invarient violation:Text strings must be rendered within a component
I am not understanding why I am getting this error ?
I have tried following solutions-
Invariant Violation: Text strings must be rendered within a <Text> component
https://github.com/facebook/react-native/issues/20084
None of them were helpful for me. So, it would be very nice if someone help me out with this.
You have used a wrong value in a header
static navigationOptions = {
header: "none"
};
Replace "none" with null
static navigationOptions = {
header: null
};
const AppStackNavigator = new StackNavigator({
WelcomeScreen: { screen: WelcomeScreen }
})
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}**,**
});
is it this comma?
I'd consider working with React's newest navigation package react-navigation-stack (currently in 2.0 alpha - link).
You would implement this exactly like previous react-navigation stack navigators.
import React from 'react'
// ...
import { createAppContainer } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
const HomeStack = createStackNavigator(
{ HomeScreen, AboutScreen },
{ initialRouteName: "HomeScreen" }
)
HomeStack.navigationOptions = {
headerShown: false, // a more concise option, to avoid future deprecation.
}
// ... continues in next code block
Don't forget to wrap your application in a react-navigation AppContainer too.
// ...
const AppNav = createAppContainer(HomeStack)
export default AppNav
Of course, if you're modifying navigationOptions in other screens, you would simply attach the alternate options within that screen component:
class HomeScreen extends React.Component {
static navigationOptions = {
headerShow: false
}
render() {
return (<View><Text>Welcome home.</Text></View>)
}
}
As seen above, we can now use the navigation option: headerShown: false.
With this new package, you'll be preparing your application for the future iterations of React's navigation packages.
Note ;'s left out as a styling choice.
I'm new to react-native/expo, and I'm currently trying to test my code and make sure that I set up react-navigation properly. When I try to run on expo on my smartphone, I get back this:
Unable to resolve module './screens/RegistrationScreen' from
'C:\Users[username]\Desktop\JDA\Smartbox\screens\HomeScreen.js': The
module './screens/RegistrationScreen could not be found from
'C:\Users[username]\Desktop\JDA\Smartbox\screens\HomeScreen.js'.
Indeed, none of these files exist...
I'm not exactly sure if I'm writing the directory wrong or not, but I can't seem to find many other situations where this is happening and find a proper solution.
import React from 'react';
import {
Image,
Platform,
ScrollView,
StyleSheet,
StatusBar,
Text,
Button,
TouchableOpacity,
View,
} from 'react-native';
import { WebBrowser } from 'expo';
import { MonoText } from '../components/StyledText';
import {createStackNavigator} from 'react-navigation';
import RegistrationScreen from './screens/RegistrationScreen';
export default class HomeScreen extends React.Component {
static navigationOptions = {
header: null,
};
onPress = () => {
this.props.navigation.navigate('Home')
};
render() {
return (
<View style={{flex: 1}}>
<View style={[{flex: 1}, styles.container]}>
<Text style={styles.getStartedText}>Manage my locks</Text>
</View>
<View style={{flex: 2}}/>
<Button style={{flex: 1}}title="Registration Test" onPress={this.onPress}>
</Button>
<Button style={{flex: 1}} title="Add new lock">
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
...Platform.select({
android: {
marginTop: StatusBar.currentHeight + 15
}
})
},
developmentModeText: {
marginBottom: 20,
color: 'rgba(0,0,0,0.4)',
fontSize: 14,
lineHeight: 19,
textAlign: 'center',
},
contentContainer: {
paddingTop: 30,
}
});
createStackNavigator({
Register: {
screen: RegistrationScreen
},
Home: {
screen: HomeScreen
}
});
The header from RegistrationScreen is like so:
import React from 'react';
import {
AppRegistry,
Button,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View
} from 'react-native';
import {createStackNavigator} from 'react-navigation';
import HomeScreen from './screens/HomeScreen';
The HomeScreen and Registration Screen are in the same directory. I'm just doing this for testing, but I want to be sure that I can navigate from this screen to registration once I press the button.
Since your HomeScreen and RegistrationScreen are in same directory your import of HomeScreen should be
import HomeScreen from './HomeScreen';
instead of
import HomeScreen from './screens/HomeScreen';
and of RegistrationScreen should be
import RegistrationScreen from './RegistrationScreen';
instead of
import RegistrationScreen from './screens/RegistrationScreen';