undefined is not an object ('evaluating _this.props.navigation.navigate') - react-native

I'm new programing with React Native and I got this issue with my code, I'm try to do a Splash screen and after that I want to make a Login that redirect me to another screen.
The Splash screen run well but when I'm in the Login Screen and I push the "Entrar" button, it crashes and shows the message.
`
import React from 'react';
import { Image, Text, View } from 'react-native';
import { Asset, SplashScreen } from 'expo';
import Splash from './screens/Splash';
import Login from './screens/Login';
import ForgotPass from './screens/ForgotPass';
import Home from './screens/Home';
App.js
export default class App extends React.Component
{
componentWillMount()
{
this.setState({
view: <Splash />
})
setTimeout(() => {
this.setState({
view: <Login />
})
}, 3000)
}
render()
{
return(
this.state.view
)
}
}
////////////////////////////////////////////////////////////
Login.js
import React from 'react';
import { View, BackHandler } from 'react-native';
import { Card, Button, FormLabel, Text, FormInput } from 'react-native-elements';
import { createStackNavigator, navigate } from 'react-navigation';
export default class Login extends React.Component
{
static navigationOptions = {
title: 'Iniciar sesión',
headerLeft: null,
}
componentDidMount()
{
BackHandler.addEventListener('hardwareBackPress', function()
{
return true;
});
}
render()
{
return (
<View style={{ paddingVertical: 20 }}>
<Card>
<FormLabel>Nombre de Usuario</FormLabel>
<FormInput placeholder='NombreUsuario' />
<FormLabel>Contraseña</FormLabel>
<FormInput secureTextEntry placeholder='Contraseña' />
<Button
buttonStyle={{ marginTop: 20 }}
backgroundColor='#03A9F4'
title='Entrar'
onPress={() => this.props.navigation.navigate('Home')}
/>
</Card>
<View style={{ paddingVertical: 20 }}>
<Button
title="¿Olvidó su contraseña?"
onPress={() => this.props.navigation.navigate('ForgotPass')}
/>
</View>
</View>
);
}
}`

you have to pass navigation props in App.js file
componentWillMount()
{
this.setState({
view: <Splash />
})
setTimeout(() => {
this.setState({
view: <Login navigation={this.props.navigation} />
})
}, 3000)
}
or you can use withNavigation in Login.js file
import { withNavigation } from 'react-navigation';
export Default withNavigation(Login);
https://reactnavigation.org/docs/en/with-navigation.html this link will help you to learn more about withNavigation in react navigation

Related

React Native Redux - Not showing updated state via different route

I'm writing a react-native app via expo and trying to implement redux. I'm not sure if I'm going about this completely the wrong way. I have a home page that has two sections, a search text box and an area with links to content pages. The content pages also contain the same search box component. I want to be able to pass the contents of the search box input to the content page so that the user doesn't need to enter this again (and will probably require access to this content further in the user journey)
My app.js looks like the below:
import React from 'react';
import 'react-native-gesture-handler';
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import ContentPage from './pages/ContentPage.js';
import LogoTitle from './components/LogoTitle';
import EventsListPage from './pages/EventsListPage.js';
import EventPage from './pages/EventPage';
import VenuePage from './pages/VenuePage';
import HomeScreen from './pages/HomePage';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const initialState ={
postcode:"abcefg"
}
const reducer = (state = initialState, action) => {
switch(action.type)
{
case 'SET_POSTCODE':
return {
postcode: action.text
}
default:
console.log("returning default state")
return state
}
}
const store = createStore(reducer);
const RootStack = createStackNavigator(
{
Home: HomeScreen,
ContentPage: ContentPage,
EventsListPage: EventsListPage,
EventPage: EventPage,
VenuePage: VenuePage
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
headerTitle: () => <LogoTitle />,
headerLeft: () => null,
headerStyle: {
backgroundColor: '#ADD8E6'
}
},
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppContainer />
</Provider>);
}
}
Homepage.js:
import React from 'react';
import { StyleSheet, View } from 'react-native';
import SearchBox from '../components/SearchBox'
import TypeDrillDownArea from '../components/TypeDrillDownArea'
import 'react-native-gesture-handler';
class HomeScreen extends React.Component {
constructor(props) {
super(props);
state = {
};
}
render() {
return (
<View style={styles.container}>
<SearchBox navigation={this.props.navigation} eventTypeId=''/>
<TypeDrillDownArea navigation={this.props.navigation} />
</View>
);
}
}
export default HomeScreen
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch'
},
});
Relevant searchbox.js:
render() {
return (
<ImageBackground source={topperBackground} style={{width: '100%'}}>
<View>
<View style={styles.row}>
<View>
<TextInput
value={this.props.postcode}
autoCapitalize="characters"
style={styles.inputBox}
placeholder="Enter Postcode"
onChangeText={(e) => this.props.setPostcode(e)}
/>
</View>
<View>
<TouchableOpacity
disabled={this.state.locationDisabled}
onPress={() => {
this.props.navigation.navigate('EventsListPage', {
navigation: this.props.navigation,
eventTypeId: this.state.eventTypeId,
locLongitude: this.state.location.coords.longitude,
locLatitude: this.state.location.coords.latitude,
});
}}>
<Image
style={styles.locationPin}
source={locationPin}
/>
</TouchableOpacity>
</View>
</View>
<View style={styles.searchButtonArea}>
<TouchableOpacity
onPress={() => {
console.log("postcode is: " + this.state.postcode)
this.props.navigation.navigate('EventsListPage', {
eventTypeId: this.state.eventTypeId,
postcode: this.props.postcode,
});
}}>
<Text style={styles.searchButton}>SEARCH</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SearchBox)
function mapStateToProps(state){
return {
postcode:state.postcode
}
}
function mapDispatchToProps(dispatch){
return{
setPostcode : (e) => dispatch({
type: 'SET_POSTCODE',
postcode : e
})
}
}
and finally relevant contentpage.js:
<View style={styles.container}>
<SearchBox navigation={this.props.navigation} eventTypeId={this.state.eventTypeId} />
<Image source={imageType(this.state.dataSource[0].eventTypeId)} style={styles.eventType} />
<Text style={styles.textToDisplay}>
{this.state.dataSource[0].eventTypeDescription}
</Text>
</View>
On load, the box is prepopulated with "abcefg" as expected. Changing the contents hits the reducer as expected. However when I navigate to a content page which loads the search box again the value is empty, regardless if I've changed the original state or not.
Am I missusing redux for what it's intended? Should I be doing this a different way?
For clarity below is the organisation of the components
In the reducer(), you are accessing action.text but in the dispatch(), you passed postcode value to postcode instead of text.

react navigation not rendering screens

I currently building a simple react native app which has two screens. I am using a react navigation to navigate between screens and when I tried following this guide https://reactnavigation.org/docs/en/hello-react-navigation.html, It doesn't render anything, just displaying a blank screen. Maybe I'm missing something that's why it doesn't render. Here's my js files:
App.js
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import Login from './src/components/screens/login';
import Order from './src/components/screens/order';
const AppNavigator = createStackNavigator(
{
Login: Login,
Order: Order
},
{
initialRouteName: 'Login',
}
);
export default class Sales extends Component {
render() {
return (
<View>
<App />
</View>
);
}
}
login.js
class Login extends Components {
static navigationOptions = {
headerShown: false,
};
render() {
return(
<View>
<Button title="Login"
onPress={() => this.props.navigation.navigate('Order')}
/>
</View >
);
}
}
order.js
class Order extends Component {
static navigationOptions = {
headerShown: false,
};
render() {
return (
<View>
<View style={styles.button}>
<Button
title="Create Order"
color='#65639E'
/>
</View>
</View>
);
}
}
const AppNavigator = createStackNavigator(
{
Login: Login,
Order: Order
},
{
initialRouteName: 'Login',
}
);
export default class Sales extends Component {
render() {
return (
<View>
<App /> // this is worng.. As there is no app component. Never wrap
//AppNavigator inside a view
</View>
);
}
}
The right thing should be. Just trying to tempelate your requirement.
class Login extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Login Screen</Text>
</View>
);
}
}
class Order extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Order Screen</Text>
</View>
);
}
}
const AppNavigator = createStackNavigator({
Login: Login,
Order: Order
});
export default createAppContainer(AppNavigator);
I hope I'm able to make my point. If any confusion do mention in the comment. More than happy to help you out.
export default class Sales extends Component {
render() {
return (
<View>
<App /> // This code right here
</View>
);
}
}
You're rendering <App /> but you don't have an App Component. Maybe try using <Login />
try this
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import Login from './src/components/screens/login';
import Order from './src/components/screens/order';
const AppNavigator = createStackNavigator(
{
Login: Login,
Order: Order
},
{
initialRouteName: 'Login',
}
);
class Sales extends Component {
render() {
return (
<View>
<AppNavigator /> --> pass here your navigation
</View>
);
}
}
export default createAppContainer(AppNavigator);

Unable to run react-navigation functions on customised back button in React native

The function I am not able to run is the navigation functions in my example it's
this.this.props.navigation.goBack()
My Login File is posted below but the part with the problem is the short snippet
The error I am getting is: TypeError: undefined is not an object (evaluating 'LogIn.props.navigation')
First failed Snippet
static navigationOptions = {
headerLeft: () => (
<Button
onPress={()=>this.props.navigation.goBack()}
title="cancel"
color={colors.black}
/>
),
};
LogIn.js
import React, { Component } from 'react';
import { PropTypes } from 'prop-types';
import Icon from 'react-native-vector-icons/FontAwesome';
import colors from '../styles/colors';
import {
View,
Text,
ScrollView,
StyleSheet,
KeyboardAvoidingView,
Button
} from 'react-native';
import InputField from '../components/form/InputField';
import NexArrowButton from '../components/buttons/NextArrowButton';
import Notification from '../components/Notification';
export default class LogIn extends Component{
constructor(props){
super(props);
this.state ={
formValid:false,
validEmail:false,
emailAddress:'',
validPassword:false,
}
this.handleNextButton = this.handleNextButton.bind(this)
this.handleCloseNotification = this.handleCloseNotification.bind(this)
this.handleEmailChange = this.handleEmailChange.bind(this);
}
static navigationOptions = {
headerLeft: () => (
<Button
onPress={()=>this.props.navigation.goBack()}
title="cancel"
color={colors.black}
/>
),
};
handleNextButton(){
if(this.state.emailAddress === 'admin#mail.com'){
this.setState({formValid:true})
} else{
this.setState({formValid: false});
}
}
handleCloseNotification(){
this.setState({formValid:true });
}
handleEmailChange(email){
const emailCheckRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const { validEmail } = this.state;
this.setState({ emailAddress: email });
if (!validEmail) {
if (emailCheckRegex.test(email)) {
this.setState({ validEmail: true });
}
} else if (!emailCheckRegex.test(email)) {
this.setState({ validEmail: false });
}
}
handlePasswordChange(password){
const { validPassword } = this.state;
this.setState({ password });
if (!validPassword) {
if (password.length > 4) {
// Password has to be at least 4 characters long
this.setState({ validPassword: true });
}
} else if (password <= 4) {
this.setState({ validPassword: false });
}
}
render(){
const {formValid, validPassword} = this.state;
const showNotification = formValid ? false:true;
const background = formValid ? colors.green01 : colors.darkOrange;
const notificationMarginTop = showNotification ? 10:0;
return(
<KeyboardAvoidingView style={[{backgroundColor:background}, styles.wrapper] } behavior="padding">
<View style={styles.ScrollViewWrapper}>
<ScrollView style={styles.ScrollView}>
<Text style={styles.loginHeader}>Log In</Text>
<InputField
labelText= "Email Address"
labelTextSize={20}
labelColor={colors.white}
textColor={colors.white}
borderBottomColor={colors.white}
inputType="email"
customStyle={{marginBottom:30}}
onChangeText={this.handleEmailChange}
/>
<InputField
labelText= "Password"
labelTextSize={20}
labelColor={colors.white}
textColor={colors.white}
borderBottomColor={colors.white}
inputType="password"
customStyle={{marginBottom:30}}
/>
</ScrollView>
<View style={styles.nextButton}>
<NexArrowButton
// handleNextButton={this.handleNextButton}
handleNextButton={()=>this.props.navigation.goBack()}
/>
</View>
<View style={[styles.notificationWrapper, {marginTop:notificationMarginTop}]}>
<Notification
showNotification={showNotification}
handleCloseNotification={this.handleCloseNotification}
type="Error"
firstLine="Those credentials don't look right."
secondLine="Please try again."
/>
</View>
</View>
</KeyboardAvoidingView>
)
}
}
const styles = StyleSheet.create({
wrapper:{
display:'flex',
flex:1,
},
ScrollViewWrapper:{
marginTop:60,
flex:1,
},
ScrollView:{
paddingLeft:30,
paddingRight:30,
paddingTop:10,
flex:1,
},
loginHeader:{
fontSize:34,
color:colors.white,
fontWeight:'300',
marginBottom:40,
},
nextButton:{
position:'absolute',
right:20,
bottom:20,
},
notificationWrapper:{
position: 'absolute',
bottom:0,
zIndex:9
}
});
The most confusing part is that the second snippet below of Login.js works perfectly and it is essentially the same thing which means that I am getting the props right, but still get the error in customised back button.
Second working snippet
<View style={styles.nextButton}>
<NexArrowButton
// handleNextButton={this.handleNextButton}
handleNextButton={()=>this.props.navigation.goBack()}
/>
</View>
App.js
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View } from 'react-native';
import LoggedOut from './src/screens/LoggedOut';
import LogIn from './src/screens/LogIn';
import LoggedIn from './src/screens/LoggedIn';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
const RootStack = createStackNavigator(
{
LoggedOut: LoggedOut,
LogIn: LogIn,
},
{
initialRouteName: 'LoggedOut',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
The error in more details
I really appreciate your help ! I am happy to provide more code if it makes it easier to debugg.
You have to change the static navigationOptions to following snippet if you want to access navigation properties in a static function:
static navigationOptions = ({ navigation }) => ({
headerLeft: () => (
<Button
onPress={()=>navigation.goBack()}
title="cancel"
color={colors.black}
/>
),
});
You don't need the this.props in this case ;) The static function does not have access to the this context so this.props will not work.

Go to detail page in a React-Native Flatlist

I made a Flatlist navigate to the detail screen when a row is clicked.
I created 4 files.
file1:
index.js
import React from 'react';
import List from "./list";
import Detail from "./detail";
import { createStackNavigator, createAppContainer } from "react-navigation";
const AppNavigator = createStackNavigator({
ListScreen: {
screen: List,
},
DetailScreen: {
screen: Detail,
},
}, {
initialRouteName: 'ListScreen',
});
export default createAppContainer(AppNavigator);
And detail.js
export default class DetailScreen extends React.PureComponent {
render() {
return (
<View
<Text>Home Details!</Text>
</View>
);
}
}
list.js
import Products from "./products";
export default class ListScreen extends React.PureComponent {
...
renderItem({ item }) {
return <Products product={item}/>
}
render() {
return (
<View style={{margin:5}}>
<FlatList
data={this.state.products}
renderItem={this.renderItem}
keyExtractor={(item,index) => item.id.toString()}
/>
</View>
);
}
And Finally
products.js
export default class ProductsType2 extends React.PureComponent {
_onPress = () => {
this.props.navigation.navigate('DetailScreen', this.props.product.id);
};
render() {
const { product} = this.props;
//const { navigate } = this.props.navigation; //get error w
return (
<Card>
<CardItem cardBody button onPress={this._onPress}>
<Image
style={{height: 140, width: 140, flex: 1}}
source={{uri: product.thumbnail}} />
</CardItem>
</Card>
);
}
}
when I press it I can't get the details screen to show up.
I get this error:
Cannot read property 'navigate' of underfined
use withNavigation (HOC) to access navigation props from products.js. That component not inside of the createStackNavigator, so export your class with withNavigation method and you can access the navigation props.
import { withNavigation } from 'react-navigation';
...
export default withNavigation(ProductsType2)
https://reactnavigation.org/docs/en/connecting-navigation-prop.html

react-native gives error on displaying image

recently started working on an app using https://github.com/start-react/native-starter-kit
Heres my component:
import React, { Component } from "react";
import { TouchableOpacity } from "react-native";
import { connect } from "react-redux";
import BlankPage2 from "../blankPage2";
import DrawBar from "../drawBar";
import TopNav from "../topNav";
import { DrawerNavigator, NavigationActions } from "react-navigation";
import {
Container,
Header,
Title,
Content,
Text,
Button,
Icon,
Left,
Body,
Right,
Image,
} from "native-base";
import { Grid, Row } from "react-native-easy-grid";
import { setIndex } from "../../actions/list";
import { openDrawer } from "../../actions/drawer";
import styles from "./styles";
class News extends Component {
static navigationOptions = {
header: null
};
render() {
return (
<Container style={styles.container}>
<Header>
<Left>
<Button
transparent
onPress={() => DrawerNav.navigate("DrawerOpen")}>
<Icon active name="menu" />
</Button>
</Left>
<Body>
<Title>News</Title>
</Body>
<Right>
</Right>
</Header>
<Content scrollEnabled={false}>
<TopNav navigation={this.props.navigation}></TopNav>
<Grid style={styles.mt}>
{this.props.list.map((item, i) => (
<Row key={i}>
<TouchableOpacity
style={styles.row}
onPress={() =>
this.props.navigation.navigate("BlankPage", {
name: { item }
})}>
<Image source={{uri: 'https://i.vimeocdn.com/portrait/58832_300x300.jpg'}} />
<Text style={styles.text}>{item}</Text>
</TouchableOpacity>
</Row>
))}
</Grid>
</Content>
</Container>
);
}
}
function bindAction(dispatch) {
return {
setIndex: index => dispatch(setIndex(index)),
openDrawer: () => dispatch(openDrawer())
};
}
const mapStateToProps = state => ({
name: state.user.name,
list: state.list.list
});
const NewsSwagger = connect(mapStateToProps, bindAction)(News);
const DrawNav = DrawerNavigator(
{
News: { screen: NewsSwagger },
BlankPage2: { screen: BlankPage2 }
},
{
contentComponent: props => <DrawBar {...props} />
}
);
const DrawerNav = null;
DrawNav.navigationOptions = ({ navigation }) => {
DrawerNav = navigation;
return {
header: null
};
};
export default DrawNav;
And of course, heres my error:
And i have no clue why this is happening. As soon as i remove the Image tag, error goes away. I can't really export the News Component, becouse i am using the Drawer thingy(check starter-kit-demo).
Edit: Error happens on IOS. Iphone 6 emulator.
You are importing Image from native-base when you should be importing it from react-native
import {
Container,
Header,
Title,
Content,
Text,
Button,
Icon,
Left,
Body,
Right,
Image // remove this one
} from "native-base";
And add
import {
TouchableOpacity,
Image
} from "react-native";
Also you'll have to add a height & width for a proper render.
<Image
style={{width: 300, height: 300}}
source={{uri: 'https://i.vimeocdn.com/portrait/58832_300x300.jpg'}}
/>