understanding "undefined is not an object('this.props.navigation.navigate)" - javascript

I am getting the error "undefined is not an object('this.props.navigation.navigate)" when I click the button titled with "Chat with Lucy" which is supposed to take me to the ChatScreen screen.
All of this code is within the App.js file i'm using that is being exported into the android and ios files.
Any reason why i'm getting this error? thanks!
import React, { Component } from 'react';
import { StackNavigator } from 'react-navigation';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TextInput,
Button
} from 'react-native';
export default class firstapp extends Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Image source={require('./Packit_title.png')} />
<TextInput
style={styles.account}
/>
<TextInput
style={styles.account}
/>
<View style={styles.button}>
<Button
title="Login"
color="#c47735"
/>
<Button
title="Sign Up"
color="#c47735"
/>
</View>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
class ChatScreen extends Component {
static navigationOptions = {
title: 'Chat with Lucy',
};
render() {
return (
<View>
<Text>Chat with Lucy</Text>
</View>
);
}
}
const firstappNav = StackNavigator({
Home: { screen: firstapp },
Chat: { screen: ChatScreen },
});
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f49542',
},
account: {
backgroundColor: '#ffffff',
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 10,
width: 200
},
button: {
flexDirection: 'row',
}
});
AppRegistry.registerComponent('firstapp', () => firstapp);

You are exporting your firstapp component which has no access to the navigation prop since nothing is being passed to it. You need to export your navigator component firstappNav instead.
AppRegistry.registerComponent('firstapp', () => firstappNav);

This is because props object is undefined in firstapp Component. You will have to override its constructor to access props. Read this

Related

I cannot use "this" on a function

I am new to React Native. I want to create a simple counter button. I could not use "this", it gives error ('this' implicitly has type 'any' because it does not have a type annotation.). You can see my TabTwoScreen.tsx TypeScript code below. I searched other questions but i could not find what to do. Why this is not working and how can I correct it. Waiting for helps. Thanks a lot.
import * as React from 'react';
import { StyleSheet, Button, Alert } from 'react-native';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View } from '../components/Themed';
export default function TabTwoScreen() {
const state={
counter: 0,
}
const but1 = () => {
this.setState({counter : this.state.counter + 1});
};
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{state.counter}</Text>
<Button
title="Increment"
onPress={but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
separator: {
marginVertical: 30,
height: 1,
width: '80%',
},
});
Error Message
App Output:
import React, { useState } from 'react';
import { StyleSheet, Button, Alert, Text, View } from 'react-native';
export default function TabTwoScreen() {
// ๐Ÿ‘‡ You are using functional components so use the useState hook.
const [counter, setCounter] = useState(0);
const but1 = () => {
// ๐Ÿ‘‡then you can increase the counter like below
setCounter(counter + 1);
};
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{counter}</Text>
<Button
title="Increment"
onPress={but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
});
And if you want to use Class based component then here is the implementation:
import React, { useState, Component } from 'react';
import { StyleSheet, Button, Alert, Text, View } from 'react-native';
export default class TabTwoScreen extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
but1 = () => {
this.setState({ counter: this.state.counter + 1 });
};
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{this.state.counter}</Text>
<Button
title="Increment"
onPress={this.but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
});
Working App: Expo Snack
Please take a look at https://reactjs.org/docs/react-component.html#setstate
Remove this from your code and let only state.count + 1
An example I did in freedcodecamp.
handleChange(event){
//event.target.value
this.setState({
input: event.target.value
});
}
// Change code above this line
render() {
return (
<div>
{ /* Change code below this line */}
<input value={this.state.input} onChange={(e) => this.handleChange(e)}/>
That is because you are using a function component. You have to either use a class based component (React class and function components) or switch over to React hooks with the useState hook.
Here's the example with a class based component:
import * as React from 'react';
import { StyleSheet, Button, Alert } from 'react-native';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View } from '../components/Themed';
export default class TabTwoScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
}
but1() {
this.setState({ counter: this.state.counter + 1 });
};
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{state.counter}</Text>
<Button
title="Increment"
onPress={this.but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}
}
And here's with React hooks:
import React, {useState} from 'react';
import { StyleSheet, Button, Alert } from 'react-native';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View } from '../components/Themed';
export default function TabTwoScreen() {
const [counter, setCounter] = useState(0);
const but1 = () => {
setCounter(counter + 1);
};
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{counter}</Text>
<Button
title="Increment"
onPress={but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}

TypeError: undefined is not an object (evaluating '_this3.state.bind')

App.js code:
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
class HomeScreen extends React.Component {
constructor(props){
super(props);
this.state={count:0};
this.incrementCount=this.incrementCount.bind(this)
}
incrementCount(){
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={styles.homeScreen}>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => {
this.incrementCount();
this.props.navigation.navigate('Details');
}}
/>
</View>
);
}
}
class DetailsScreen extends React.Component {
constructor(props){
super(props);
this.state=this.state.bind(this)
this.incrementCount=this.incrementCount.bind(this)
}
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Hello </Text>
</View>
);
}
}
const AppNavigator = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
}
);
const styles= StyleSheet.create({
homeScreen:{
}
});
export default createAppContainer(AppNavigator);
I wanted to increment a number (0), every time the user goes to the details(the second page) page. The incremented number should be displayed on the details(the second page) page.
I am a beginner in react native and I don't know how to use state in different classes. Do explain the concept of state along with the solution.
You have to send your count as prop to your DetailsPage. So in code it will look like this:
<Button
title="Go to Details"
onPress={() => {
this.incrementCount();
this.props.navigation.navigate('Details',{count:this.state.count});
}}/>
And in your DetailsScreen you have to access it like this:
class DetailsScreen extends React.Component {
constructor(props){
super(props);
//Remove these lines this is causing error and this is wrong
//this.state=this.state.bind(this)
//this.incrementCount=this.incrementCount.bind(this)
}
render() {
let count = this.props.navigation.getParam('count')
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>You were here {count} times </Text>
</View>
);
}
}

"Route 'HomeScreen' should declare a screen" occuring for one of my components and i dont know why

I have been trying to implement react-navigation to my project to very little success.
Every time i import a screen to the navigator it comes up as "undefined".
I have tried loading just the screen to the top level and it seems to work but when i put it inside the navigation it returns to being undefined.
Heres my code:
index.js:
import React, { Component } from 'react';
import Root from './navigator/router';
//import Home from './screens/Home';
export class App extends Component {
render() {
return <Root />;
}
}
Home.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Slider,
Image,
ListView,
ScrollView,
TouchableOpacity
} from 'react-native';
import HeatingSliderComponent from '../components/HeatingSliderComponent';
export default class Home extends Component {
_onPressDial = () => {
this.props.navigation.navigate('DialScreen');
};
render() {
return (
<View style={styles.container}>
{/* Navigation bar */}
<View style={styles.navBarOuter}>
<View style={styles.navBarInner}>
{/* item 1 */}
<TouchableOpacity flex = {1}>
<Image
//style={styles.button}
source={require('../../images/menu_logout.png')}
/>
</TouchableOpacity>
{/* item 2 */}
<Image
flex = {3}
style = {{resizeMode: 'contain'}}
source={require('../../images/background_text.png')}
/>
{/* item 3 */}
<TouchableOpacity flex = {1}>
<Image
//style={styles.button}
source={require('../../images/menu_about.png')}
/>
</TouchableOpacity>
</View>
</View>
<View style = {styles.oneFlexGap}/>
{/* Main Dial Button */}
<View style={styles.dialButton}>
<TouchableOpacity onPress={this._onPressDial}>
<Image
//figure out how to make this work and maybe look into making a custom wheel of some kind.
//probably by writing in native android
style={styles.button}
source={require('../../images/menu_edit_4.png')}
/>
</TouchableOpacity>
</View>
{/*<View style = {styles.oneFlexGap}/>*/}
{/* Vertical Slider */}
{/*<View style = {styles.vertSliderContainer}>
<HeatingSliderComponent
step={1}
minimumValue={0}
maximumValue={100}
value={0}
/>
</View>*/}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 5,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
navBarInner: {
flex: 1,
flexDirection: 'row',
height: '5%',
width: '100%',
alignItems: 'center',
},
navBarOuter: {
flex: 2,
alignItems: 'center',
},
vertSliderContainer: {
flex: 2,
alignItems: 'center',
},
dialButton: {
flex: 2,
alignItems: 'center',
},
button: {
flex: 1
},
oneFlexGap: {
flex: 1
},
});
AppRegistry.registerComponent('Home', () => Home);
router.js:
import React from 'react';
import { StackNavigator } from 'react-navigation';
import DialScreen from '../screens/DialScreen';
import Home from '../screens/Home';
export const Root = StackNavigator({
HomeScreen: {
screen: Home,
},
DialScreen: {
screen: DialScreen,
navigationOptions: {
title: 'DialScreen',
},
},
});
I have tried a multitude of things to try and get it to work including making the project again in a new location.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UPDATE: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I am still facing these errors but now i am facing the error "Route 'HomeScreen' should declare a screen error.
With my last change i did this to the router.js
// import DialScreen from '../screens/DialScreen';
// import Home from '../screens/Home';
var DialScreen = require('../screens/DialScreen');
var Home = require('../screens/Home');
and then structured the objects like this
DialScreen: {
screen: DialScreen.DialScreen,
navigationOptions: {
title: 'DialScreen',
},
from these changes i seem to get this error instead.
Route 'DialScreen' should declare a screen. For example:
import MyScreen from './MyScreen';
...
DialScreen: {
screen: MyScreen,
}
<unknown>
C:\Users\Dell\Documents\DSMReact\node_modules\react-navigation\src\routers\validateRouteConfigMap.js:22:6
validateRouteConfigMap
C:\Users\Dell\Documents\DSMReact\node_modules\react-navigation\src\routers\validateRouteConfigMap.js:18:21
default
C:\Users\Dell\Documents\DSMReact\node_modules\react-navigation\src\routers\StackRouter.js:36:25
default
C:\Users\Dell\Documents\DSMReact\node_modules\react-navigation\src\navigators\StackNavigator.js:44:29
loadModuleImplementation
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\packager\src\Resolver\polyfills\require.js:174:12
guardedLoadModule
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\packager\src\Resolver\polyfills\require.js:119:45
_require
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\packager\src\Resolver\polyfills\require.js:110:24
_accept
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\packager\src\Resolver\polyfills\require.js:274:12
<unknown>
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\Libraries\Utilities\HMRClient.js:121:27
onmessage
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\Libraries\Utilities\HMRClient.js:101:26
dispatchEvent
C:\Users\Dell\Documents\DSMReact\node_modules\event-target-shim\lib\event-target.js:172:43
<unknown>
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\Libraries\WebSocket\WebSocket.js:148:27
emit
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\Libraries\EventEmitter\EventEmitter.js:182:12
__callFunction
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:245:47
<unknown>
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:101:26
__guard
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:213:6
callFunctionReturnFlushedQueue
C:\Users\Dell\Documents\DSMReact\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:100:17
error message
Change from this in the index.js file
import Root from './navigator/router';
to
import { Root } from './navigator/router';
and this is because you are doing a named export on the Root StackNavigator.
------------------------------ OR -------------------------------
Instead of the previous solution, you change the export of the Root in the router.js file to a default export like so
const Root = StackNavigator({...});
at the bottom, you place the default export statement
export default Root;
Cheers!

How to render a loader until data is fetched in React Native

I am fetching data through an async request. I know that I need to wait for the api request to complete before displaying the data. Unfortunately, I'm not sure how to create a loader to wait for the data to load.I am new to react, so if I could also get help with implementing it as well, that would be fantastic! Here is my current code:
import React, { Component, PropTypes } from 'react';
import { View, Text, ListView, StyleSheet, TouchableHighlight} from 'react- native';
import Header from '../Components/Header';
import Api from '../Utility/Api';
export default class CalendarPage extends Component {
constructor(props) {
super(props);
}
async componentWillMount() { this.setState(
{data: await Api.getDates()},
)
}
render() {
return (
<View style={{flex: 1}}>
<Header pageName="Calendar" navigator={this.props.navigator}/>
<View style = {{flex:9}}>
<View>
{ this.state.data.days[0].items.map((item) => (
<View>
<Text>{item.summary}</Text>
<Text>{item.start.dateTime}</Text>
<Text>{item.description}</Text>
</View>
))}
</View>
</View>
</View>
);
}
}
A simple example using ActivityIndicator -
import ActivityIndicator
import { View, Text, ListView, StyleSheet, TouchableHighlight, ActivityIndicator} from 'react- native';
set data state to null
constructor(props) {
super(props);
this.state = {
data: null
}
}
do conditional rendering
render() {
if (!this.state.data) {
return (
<ActivityIndicator
animating={true}
style={styles.indicator}
size="large"
/>
);
}
return (
<View style={{flex: 1}}>
<Header pageName="Calendar" navigator={this.props.navigator}/>
....
....
</View>
);
}
}
indicator style
const styles = StyleSheet.create({
indicator: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
height: 80
}
});
Although solution proposed by #vinayr works fine but user will still be able to click on screen and perform some action even while loader is being shown which can lead to crash.
One solution is wrap loader inside a Modal.
import React, { Component } from 'react';
import {
StyleSheet,
View,
Modal,
ActivityIndicator,
} from 'react-native';
const styles = StyleSheet.create({
modalBackground: {
flex: 1,
alignItems: 'center',
flexDirection: 'column',
justifyContent: 'space-around',
backgroundColor: '#00000040',
},
activityIndicatorHolder: {
backgroundColor: '#FFFFFF',
height: 100,
width: 100,
borderRadius: 10,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-around',
},
});
const SmartLoader = (props) => {
const {
isLoading,
...attributes
} = props;
return (
<Modal
transparent
animationType={'none'}
visible={isLoading}
onRequestClose={() => { console.log('Noop'); }}
>
<View style={styles.modalBackground}>
<View style={styles.activityIndicatorHolder}>
<ActivityIndicator
animating={isLoading}
size="large"
/>
</View>
</View>
</Modal>
);
};
export default SmartLoader;
After that you can use it anywhere in your component, user will not be able to perform any action till loader is finished ( made hidden based on flag)

How to navigate page with React Native

I have a component for listing items, I want to add the function that can go to a different page, and that page has the detail about that item. Currently, this is my code for listing items.
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import axios from 'axios';
import CarDetail from './CarDetail';
const API_URL = 'http://localhost:3000';
class CarList extends Component {
state = { cars: [] };
componentWillMount() {
console.log('Mount');
axios.get(`${API_URL}/cars`)
.then(response => this.setState({ cars: response.data.cars }));
}
renderCars() {
return this.state.cars.map(car => <CarDetail key={car.id} car={car} />
);
}
render() {
console.log(this.state.cars);
return (
<ScrollView>
{this.renderCars()}
</ScrollView>
);
}
}
export default CarList;
and this is the code for describing items
import React from 'react';
import { Text, View, Image } from 'react-native';
import { Actions } from 'react-native-router-flux';
import Card from '../material/Card';
import CardSection from '../material/CardSection';
const CarDetail = ({ car }) => {
const imageURI = 'https://yt3.ggpht.com/-HwO-2lhD4Co/AAAAAAAAAAI/AAAAAAAAAAA/p9WjzQD2-hU/s900-c-k-no-mo-rj-c0xffffff/photo.jpg';
const { make, model } = car;
function showCarDetail() {
Actions.showCar();
}
return (
<Card>
<CardSection>
<View style={styles.containerStyle}>
<Image
style={styles.imageStyle}
source={{ uri: imageURI }}
/>
</View>
<View style={styles.headContentStyle}>
<Text
style={styles.headerTextStyle}
onPress={showCarDetail()}
>
{make}
</Text>
<Text>{model}</Text>
</View>
</CardSection>
<CardSection>
<Image
style={styles.picStyle}
source={require('./car.jpg')}
/>
</CardSection>
</Card>
);
};
const styles = {
headContentStyle: {
flexDirection: 'column',
justifyContent: 'space-around'
},
headerTextStyle: {
fontSize: 18
},
imageStyle: {
height: 50,
width: 50
},
containerStyle: {
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
marginRight: 10
},
picStyle: {
height: 300,
flex: 1,
width: null
}
};
export default CarDetail;
How can I change my code for that? Can anyone give me an example?
You have to use some sort of navigation component. There are many out there, but personally I use the one that is built into React Native. https://facebook.github.io/react-native/docs/navigator.html

Categories

Resources