I'm trying to create a React Native app with some basic routing.
This is my code so far:
App.js:
import React from 'react'
import { StackNavigator } from 'react-navigation'
import MainScreen from './classes/MainScreen'
const AppNavigator = StackNavigator(
{
Index: {
screen: MainScreen,
},
},
{
initialRouteName: 'Index',
headerMode: 'none'
}
);
export default () => <AppNavigator />
MainScreen.js:
import React, { Component } from 'react'
import { StyleSheet, Text, View, Button, TouchableOpacity, Image } from 'react-native'
import HomeButton from './HomeButton'
export default class MainScreen extends Component {
static navigatorOptions = {
title: 'MyApp'
}
constructor(props) {
super(props)
}
render() {
return (
<View style={styles.container}>
<Image source={require('../img/logo.png')} style={{marginBottom: 20}} />
<HomeButton text='Try me out' classType='first' />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
})
HomeButton.js:
import React, { Component } from 'react'
import { StyleSheet, Text, View, Button, TouchableOpacity } from 'react-native'
import { StackNavigator } from 'react-navigation'
export default class HomeButton extends Component {
constructor(props) {
super(props)
}
render() {
return (
<TouchableOpacity
onPress={() => navigate('Home')}
style={[baseStyle.buttons, styles[this.props.classType].style]}
>
<Text style={baseStyle.buttonsText}>{this.props.text.toUpperCase()}</Text>
</TouchableOpacity>
)
}
}
var Dimensions = require('Dimensions')
var windowWidth = Dimensions.get('window').width;
const baseStyle = StyleSheet.create({
buttons: {
backgroundColor: '#ccc',
borderRadius: 2,
width: windowWidth * 0.8,
height: 50,
shadowOffset: {width: 0, height: 2 },
shadowOpacity: 0.26,
shadowRadius: 5,
shadowColor: '#000000',
marginTop: 5,
marginBottom: 5
},
buttonsText: {
fontSize: 20,
lineHeight: 50,
textAlign: 'center',
color: '#fff'
}
})
const styles = {
first: StyleSheet.create({
style: { backgroundColor: '#4caf50' }
})
}
Everything works fine, but when pressing the button I get
Can't find variable: navigate
I've read that I have to declare it like this:
const { navigate } = this.props.navigation
So I edited HomeButton.js and added that line at the beginning of the render function:
render() {
const { navigate } = this.props.navigation
return (
<TouchableOpacity
onPress={() => navigate('Home')}
style={[baseStyle.buttons, styles[this.props.classType].style]}
>
<Text style={baseStyle.buttonsText}>{this.props.text.toUpperCase()}</Text>
</TouchableOpacity>
)
}
Now I get:
TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')
It seems that the navigation object is not coming into the properties, but I don't understand where should I get it from.
What am I missing here?
React-navigation pass navigation prop to the screen components defined in the stack navigator.
So in your case, MainScreen can access this.props.navigation but HomeButton can't.
It should work if you pass navigation prop from MainScreen to HomeButton :
<HomeButton text='Try me out' classType='first' navigation={this.props.navigation}/>
Edit: You have to define the Homescreen in your stack navigator in order to navigate to it, your onPress={() => navigate('Home')} won't work until then.
Related
So I have my App.js which then renders a NavigationContainer with MainStack.Screen(s). I use an api to fetch some data about movies and then process it to give me a list of movieItem Objects with details about that movie. I save this moviesList object in my App.js state and want to pass this to my HomeScreen so that it can render all the movies in the moviesList object.
Please help how I can correctly get the route.params.moviesList[0].title to show.
App.js:
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import HomeScreen from './Screens/HomeScreen';
import ResultsScreen from './Screens/ResultsScreen';
import { fetchMovies } from './api';
const MainStack = createStackNavigator();
export default class App extends React.Component {
state = {
moviesList: null,
};
componentDidMount() {
this.getUsers();
}
getUsers = async () => {
const movies = await fetchMovies();
this.setState({ moviesList: movies });
console.log('===========');
console.log(this.state.moviesList);
};
render() {
return (
<NavigationContainer>
<MainStack.Navigator>
<MainStack.Screen
name="Home"
component={HomeScreen}
initialParams={this.state}
/>
<MainStack.Screen name="Results" component={ResultsScreen} />
</MainStack.Navigator>
</NavigationContainer>
);
}
}
HomeScreen.js:
import React from 'react';
import { StyleSheet, TextInput, Button, Text, View } from 'react-native';
import Row from '../Row';
export default function HomeScreen({ route, navigation }) {
console.log('ROUTE:');
console.log(route);
return (
<View style={styles.container}>
<Text style={styles.heading}>Movie Browser</Text>
<Text style={styles.heading}>{route.params.moviesList[0].title}</Text>
<TextInput style={styles.textInput} placeholder="Sreach" />
<Row props />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
},
heading: {
fontSize: 42,
padding: 20,
},
text: {
justifyContent: 'center',
fontSize: 24,
paddingBottom: 5,
},
textInput: {
borderWidth: 2,
borderColor: 'black',
minWidth: 260,
marginBottom: 20,
marginHorizontal: 20,
paddingHorizontal: 10,
paddingVertical: 5,
borderRadius: 3,
},
});
I believe the movieList array is your params. Try this in your return statement of HomeScreen.js:
<Text style={styles.heading}>{route.params[0].title}</Text>
I am struggling a little bit. I have tried to create more components for my React native app but after I did it my ButtonSaving stoped redirecting to Dashboard for some reason. I was trying some ways to pass onRowPress to component but without luck. What do I do incorrectly here please?
Login button is working fine => redirecting to Dashboard
ButtonSaving not working at all => should redirect to Dashboard
AppNavigator.js
import { createStackNavigator } from 'react-navigation-stack'
import { createAppContainer } from 'react-navigation';
import Homepage from './components/Homepage/Homepage';
import Dashboard from './components/Dashboard/Dashboard';
const AppNavigator = createStackNavigator({
Homepage: Homepage,
Dashboard: { screen: Dashboard},
},
{
initialRouteName: 'Homepage',
defaultNavigationOptions: {
headerStyle: {
backgroundColor: 'white',
opacity: 70,
borderBottomColor: 'white',
borderColor: 'white'
},
headerTintColor: 'black',
headerTitleStyle: {
fontWeight: 'bold'
}
}
}
);
const Container = createAppContainer(AppNavigator);
export default Container;
Homepage.js
import React from 'react';
import { StyleSheet, Text, View, Button, Image } from 'react-native';
import {NavigationActions} from 'react-navigation';
// COMPONENTS
import ButtonSaving from './ButtonSaving/ButtonSaving';
class Homepage extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false
},
this.handleClick = this.handleClick.bind(this);
this.onRowPress = this.onRowPress.bind(this);
}
handleClick() {
const counterApp = this.state.counter;
this.setState({
counter: counterApp + 1,
dashboard: 'Dashboard'
})
}
onRowPress = ({ navigation }) => {
this.props.navigation.navigate(this.state.dashboard);
}
render() {
return(
<View style={styles.container}>
{/* LOGIN BUTTON */}
<View style={styles.buttonContainer}>
<View style={styles.buttonLogin}>
<Button title="log in"
color="white"
onPress={() => this.props.navigation.navigate('Dashboard')}/>
</View>
</View>
{/* LOGO CONTAINER */}
<View style={styles.logoContainer}>
<Image
style={{height: 147, width: 170}}
source= {require('./REACT_NATIVE/AwesomeProject/logo.png')}
></Image>
</View>
{/* EXPLAINATION OF WALT */}
<Text style={styles.textContainer}>Lorem ipsum lorem upsum></Text>
{/* Needs to be refactored to VIEW */}
<ButtonSaving onPress={() => this.onRowPress}/>
</View>)
}
ButtonSaving.js
import React from 'react';
import { StyleSheet, Text, View, Button, Image, TouchableOpacity } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
class ButtonSaving extends React.Component {
constructor(props) {
super(props);
this.state = {
},
this.onRowPress = this.onRowPress.bind(this);
}
onRowPress = ({ navigation }) => {
this.props.navigation.navigate(this.state.dashboard);
}
render(){
return(
<View style={styleButton.container}>
<LinearGradient
colors={[
'#00b38f',
'#7dcf5a'
]}
style={styleButton.opacityContainer}>
<TouchableOpacity>
<Button
title="Start Saving"
color='white'
onPress={this.onRowPress}/>
</TouchableOpacity>
</LinearGradient>
</View>
)
}
}
const styleButton = StyleSheet.create({
container: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
width: '100%',
height: 50,
justifyContent: 'center',
marginTop: '39%'
},
opacityContainer: {
height: 48,
borderRadius: 25,
backgroundColor: 'darkgreen',
width: '70%',
justifyContent: 'center',
alignItems: 'center'
}
})
export default ButtonSaving;
You miss to put dashboard in your state in ButtonSaving.js
In Homepage.js when your are calling handleClick ?. Dunno how you got that working...
You say in the onRowPress this:
this.props.navigation.navigate(this.state.dashboard);
but I don't see anywhere that you set this.state.dashboard.
Probabbly you missed set it up.
It was simple refactor and this helped!
<ButtonSaving navigation ={this.props.navigation}/>
I will update solution for others later.
There is no point to save "dashboard" in the Homepage state or the ButtonSaving state.
In Homepage.js you don't need to pass onPress to ButtonSaving
...
<ButtonSaving navigation={this.props.navigation}/>
...
Next in ButtonSaving.js
onRowPress = () => {
this.props.navigation.navigate('Dashboard');
}
I am trying to add a simple customized navigation menu to my react-native app, but the issue that I am coming across right now is that I can't seem to find a way to navigate to the selected menu items corresponding screen. I tried the normal this.props.navigation.navigate('Home'), but it seems that there is no navigation prop, which makes sense because in my app I am assuming that the prop for navigation is passed down to the screens from my app.js through the use of <AppContainer />.
I have tried using the MainNavigator object in my App.js but it doesn't seem to be working and doesn't have a navigate function or anything like that.
I have also tried changing the structure of my render function in App.js a little bit but it still does not seem to be having much of an effect.
This is my App.js
import React, { Component } from 'react';
import {
View,
Text,
TouchableOpacity
} from 'react-native';
import {
createStackNavigator,
createAppContainer } from 'react-navigation';
// SCREEN
import MainScreen from './screens/MainScreen';
import CostAnalysis from './screens/CostAnalysis';
import DriverLog from './screens/DriverLog';
// SIDE MENU
import SideMenu from 'react-native-side-menu';
// REDUX IMPORTS
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { recordReducer } from './reducers/recordReducer';
import { databaseReducer } from './reducers/databaseReducer';
const MainNavigator = createStackNavigator({
Home: {screen: MainScreen},
DriverLog: {screen: DriverLog},
CostAnalysis: {screen: CostAnalysis},
}, {
defaultNavigationOptions: {
header: null
}
});
const AppContainer = createAppContainer(MainNavigator);
const rootReducer = combineReducers(
{records: recordReducer,
database: databaseReducer});
const store = createStore(rootReducer);
class App extends Component {
render() {
const menu = (<View style={{
backgroundColor: '#f0f0f0',
alignContent: 'center',
textAlign: 'center', height: '100%', width: '100%', paddingTop: '40%'}}>
<Text style={styles.menuTitle}>{'S K I P\nD R I V E R\nL O G'}</Text>
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Home')}}>
<Text style={styles.menuItem}>HOME</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {MainNavigator.navigate('DriverLog')}}>
<Text style={styles.menuItem}>DRIVING LOG</Text>
</TouchableOpacity>
</View>);
return (
<SideMenu menu={menu} >
<Provider store={store}>
<AppContainer />
</Provider>
</SideMenu>
);
}
}
const styles = {
menuTitle: {
marginBottom: 60,
fontSize: 40,
textAlign: 'center',
color: '#e74c3c'
},
menuItem: {
marginBottom: 10,
fontSize: 26,
textAlign: 'center'
}
}
export default (App);
Ideally I don't have to re-structure my entire app as I have made a lot of progress in other areas, but I would really like the menu to simply link to the correct places.
I'm still very new to react-native so I really don't know what else to try. If anyone can give me a hand it would be greatly appreciated!
Thanks :)
PS: See a picture of the menu to illustrate what I mean
Menu Screenshot
you have to implement the constructor
class App extends Component {
constructor(props) {
super(props);
}
}
or
if you are using a drawer use it as a separate component
import React, { Component } from 'react';
import {
View,
Text,
TouchableOpacity
} from 'react-native';
class SideDrawer extends Component{
constructor(props) {
super(props);
}
render(){
return(
<View style={{
backgroundColor: '#f0f0f0',
alignContent: 'center',
textAlign: 'center', height: '100%', width: '100%', paddingTop: '40%'}}>
<Text style={styles.menuTitle}>{'S K I P\nD R I V E R\nL O G'}</Text>
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Home')}}>
<Text style={styles.menuItem}>HOME</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {MainNavigator.navigate('DriverLog')}}>
<Text style={styles.menuItem}>DRIVING LOG</Text>
</TouchableOpacity>
</View>
)
}
}
export default sideDrawer
then in your navigator
const HomeNavigator = StackNavigator(
Home: {screen: MainScreen},
DriverLog: {screen: DriverLog},
CostAnalysis: {screen: CostAnalysis},
}
const MainNavigator = DrawerNavigator({
Home: {
screen: HomeNavigator,
},
}, {
contentComponent: sideDrawer,
drawerWidth: width * .7,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});
I'm new to react native, but I've been researching how to redirect to new activities with buttons for the last few hours with no avail. My current solution involves me using react-navigation from multiple files, with App.js creating the StackNavigator for the rest of the pages. However, whenever I press the button on Initial.js, nothing happens.
I followed Damien Manson's tutorial on Invariant Violation: The navigation prop is missing for this navigator, but the button still doesn't work. I tried referencing App before calling my button, but whenever I try to run it on the emulator, it doesn't show me an error log and it never loads. It stays at "Downloading JavaScript bundle: 100%" for minutes until the emulator itself crashes.
Here's my App.js
import Initial from './components/Initial'
import Statistics from './components/Statistics'
const RootStack = createStackNavigator({
Default: {
screen: Initial
},
Stats: {
screen: Statistics
}
});
const App = createAppContainer(RootStack);
export default App;
Here's my Initial.js
import { StyleSheet, ImageBackground, Image, View, Text, Button } from 'react-native';
import { Font } from 'expo';
import App from '../App';
import {withNavigation} from 'react-navigation';
import Statistics from './Statistics';
export default class Initial extends React.Component {
static navigationOptions = {header: null}
componentDidMount() {
Font.loadAsync({'pt': require('../assets/fonts/pt.ttf')});
Font.loadAsync({'Karla': require('../assets/fonts/Karla-Regular.ttf')});
Font.loadAsync({'Space-Mono': require('../assets/fonts/SpaceMono-Regular.ttf')});
}
state = { fontLoaded: false};
async componentDidMount() {
await Font.loadAsync({'pt': require('../assets/fonts/pt.ttf'),});
await Font.loadAsync({'Karla': require('../assets/fonts/Karla-Regular.ttf'),});
await Font.loadAsync({'Space-Mono': require('../assets/fonts/SpaceMono-Regular.ttf'),});
this.setState({fontLoaded: true});
}
render() {
return (
<ImageBackground
source = {require('../assets/blue-bin.jpg')}
style = {styles.container}>
<View style = {styles.parentView}>
{this.state.fontLoaded ? (<Text style={styles.logoText}>!arbitrary</Text>) : null}
<Image source = {require('../assets/sadparrot.gif')} style = {styles.logo}/>
<Text style = {styles.textBox}>With its easily navigatible interface, the Chicago-based app, !arbitrary, aims to educate the masses about recyclable items, while emphasizing the importance of being sustainable.</Text>
<View style = {styles.redirect}>
<Button
title="Start"
onPress={() => this.props.navigation.navigate('Statistics')}
/>
</View>
</View>
</ImageBackground>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
width: '100%',
height: '100%',
},
parentView: {
flex: 1,
flexDirection: 'column',
backgroundColor: 'rgba(5,9,12, 0.6)',
justifyContent: 'center',
alignItems: 'center'
},
logoText: {
color: '#fff',
fontSize: 36,
fontFamily: 'pt'
},
textBox: {
width: 200,
height: 175,
fontFamily: 'sans-serif',
fontSize: 14,
color: '#fff',
borderColor: '#fff',
borderWidth: 2,
justifyContent: 'center',
marginTop: 50,
padding: 20
},
logo: {
width: 200,
height: 200
},
redirect: {
width: 80,
height: 30,
marginTop: 30
},
statistics: {
flex: 1,
width: '100%',
height: '100%',
backgroundColor: '#1B384F'
},
bigText: {
color: '#fff',
fontSize: 20,
fontFamily: 'Space-Mono'
}
});
Here's my Statistics.js
import { StyleSheet, ImageBackground, Image, View, Text, Button } from 'react-native';
import { Font } from 'expo';
import {withNavigation} from 'react-navigation';
class Statistics extends React.Component {
render() {
return(
<Text>Avail!</Text>
);
}
}
export default withNavigation(Statistics);
NOTE: I omitted my StyleSheet in Initial.js for the sake of being concise.
You need to navigate to your screen name which is Stats.
<Button
title="Start"
onPress={() => this.props.navigation.navigate('Stats')}/>
I had the same issue. I fixed is by using withNavigation
In Statistics class,
1st, Import withNavigation.
import { withNavigation } from 'react-navigation';
Then, export Statistics class as below.
export default withNavigation(Statistics)
Try this
const RootStack = createStackNavigator({
Default: {
screen: Initial
},
Stats: {
screen: props => <Statistics {...props} />
}
});
I want to create some screen with stack and tabs navigator, but it seems not worked, it get error message like this error on virtual device...
Is this because the navigation or what?
This is my code
ConfirmActivation.js
import React, { Component } from 'react';
import { StyleSheet, Image } from 'react-native';
import { Container, Header, Content, Left, Right, Body, Text, StyleProvider,
Form, Item, Input, Label, Button, View } from 'native-base';
import { StackNavigator } from 'react-navigation';
import Icon from 'react-native-vector-icons/FontAwesome';
import getTheme from '../../../native-base-theme/components';
import material from '../../../native-base-theme/variables/material';
import Index from '../tabs/Index';
export default class sharpcs extends React.Component {
static navigationOptions = {
title: <Image source={require('../../assets/img/sharp_logo.png')} style={{width: 200, height: 50}} />,
header: null
}
render() {
return (
<AppNavigation/>
);
}
}
class ConfirmActivation extends Component{
static navigationOptions = {
title: <Image source={require('../../assets/img/sharp_logo.png')} style={{width: 200, height: 50}} />,
header: null
}
render() {
const { navigate } = this.props.navigation;
return (
<StyleProvider style={getTheme(material)}>
<Container style={styles.container} >
<Form style={styles.form} >
<Item floatingLabel>
<Label>Masukkan kode verifikasi</Label>
<Input keyboardType = 'numeric' maxLength = {13} />
</Item>
<View style={styles.buttonContainer} >
<Button
onPress={() =>
navigate('MainScreen')
} success style={{width: 125}} >
<Label style={{color: '#FFF', marginLeft: 24}} >
Lanjut
</Label>
</Button>
</View>
</Form>
</Container>
</StyleProvider>
);
}
}
const App = StackNavigator({
ThisScreen: { screen: ConfirmActivation },
MainScreen: { screen: Index }
});
const AppNavigation = () => (
<App />
);
const styles = StyleSheet.create({
form: {
flex: 2,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center'
},
container: {
padding: 20
},
buttonContainer: {
marginTop: 20,
flexDirection: 'row',
alignSelf: 'flex-end'
}
});
Index.js
import React, { Component } from 'react';
export default class Index extends React.Component {
render() {
return null;
}
}
The cause of the error is the title in the navigationOptions in sharpcs class. It expects a string. You had provided it an image component. Although the image appears, but this error appears when navigating. So use instead of title, headerTitle