undefined is not an object (evaluating '_this.props.navigator.push') - javascript

I'm trying to navigate from Homescreen to another screen(Test).I have 'HomeScreen.js' below. Once I click on the register button, I get the above mentioned error.
I've been at this for a whole day, but can't seem to get a straight forward answer.
The error is on my 'Homescreen.js' (Attached screenshot error)
Screenshot
Error is pointing to: this.props.navigator.push under the _handleRegisterView function.
HomeScreen.js
import React from 'react';
import {
StyleSheet,
Text,
View,
AsyncStorage,
Component,
TouchableHighlight,
AppRegistry
} from 'react-native';
import Test from './Test';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'SpeedHack',
};
_handleRegisterView = () => {
this.props.navigator.push({
title: 'Test',
component: Test,
backButtonTitle: 'Back'
})
//alert('Register button Pressed!.');
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this._handleRegisterView}>
<Text style={[styles.button, styles.blueButton]}>
Register
</Text></View>
);
}
}
Test.js (Doesn't really do anything interesting, loads an image)
import React from 'react';
import { Component, StyleSheet, Text, View, Image } from 'react-native';
class Test extends React.Component {
render() {
let pic = {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
};
return (
<View style={styles.container}>
<Text>Ssup Dude! Want some bananas?</Text>
<Image source = {pic} style = {{width: 300, height: 300}}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

You seem to be confused. In react-navigation in order to push a screen, you do not do this.props.navigator.push, you use this.props.navigation.navigate.

Related

React native issue with navigation"

so I am really having a hard time with this navigation thing. I am not an expert in Js or react native, but since the person working on this app isn't in the company anymore, I am asked to make some tweaks here and there until a new person comes in but I am struggling with this navigation thing.
so I am using this to go to my two factor identification
any idea what does this navigate do anyway? how can I set it value? do it need to passe it somehow?
full code
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {
View,
Text,
TouchableHighlight,
Image,
TextInput,
} from 'react-native'
import {requiredFields} from '../helpers/forms'
import BusyButton from '../Common/BusyButton'
import DismissKeyboard from '../Common/DismissKeyboard'
import {Colors} from '../styles'
import LoginStyles from './LogInStyles'
const loginStyles = LoginStyles.createStyles()
/* eslint-disable camelcase,space-before-function-paren */
export default class TwoFactor extends Component {
static propTypes = {
screenProps: PropTypes.object.isRequired,
navigation: PropTypes.object.isRequired,
}
state = {
verificationCode: '',
}
handleSubmit = () => {
try{
const {screenProps: {auth: {sendVerificationCode}}, navigation: {navigate}} = this.props
if (requiredFields(['verificationCode'], ['Verification Code'], this.state)) {
sendVerificationCode(this.state.verificationCode,this.state.user, navigate)
}
return false
}catch(e){
console.log(e)
}
}
render() {
const {screenProps: {auth: {isFetching}}} = this.props
return (
<DismissKeyboard style={loginStyles.pageWrapper}>
<View style={loginStyles.logoContainer}>
<Image
style={loginStyles.logo}
resizeMode="contain"
source={require('../../assets/images/logo-IH_blue_gold-small.png')}
/>
</View>
<View style={loginStyles.containerExpand}>
<Text style={loginStyles.h1}>ID Verification</Text>
<Text style={loginStyles.label}>
A verification code has been sent to the phone number on file. Please enter the code below.
</Text>
<TextInput
style={loginStyles.input}
placeholder="Verification Code"
placeholderTextColor={Colors.lightGray}
onChangeText={(verificationCode) => this.setState({verificationCode})}
keyboardType="number-pad"
/>
</View>
<View style={loginStyles.container}>
<View style={loginStyles.buttonContainer}>
<BusyButton
style={loginStyles.button}
underlayColor={Colors.buttonPrimaryBkgd}
isBusy={isFetching}
onPress={this.handleSubmit}
>
<Text style={loginStyles.buttonText}>Next</Text>
</BusyButton>
</View>
</View>
</DismissKeyboard>
)
}
}
ERROR
it's not spitting any error, but it is not taking me to the next screen.

Import JSON file dynamically in React-native

I want to import JSON files dynamically based on certain condition. My Code is
import TXT1 from "../Assets/TTCS1.json";
import TXT2 from "../Assets/TTCS2.json";
export class Timetable extends Component {
state = {class: 1};
render() {
return this.state.class === 1 ? (
<View style={styles.container}>
<Text>{TXT1.S5}</Text>
</View>
) : (
<View style={styles.container}>
<Text>{TXT2.S5}</Text>
</View>
);
}
}
These JSON files are large and a particular user will mostly use only any one of the JSON file hence importing all is waste of resources. I found an answer here How can I conditionally import an ES6 module? the answer works fine with JS files, but with JSON files I am confused what is to be put in .then() function.
you can use require.
Created expo snack :
https://snack.expo.io/BJRqgSnqr
import React, { Component } from 'react';
import { Text, View, StyleSheet, ScrollView } from 'react-native';
import * as Constants from 'expo-constants';
var TXT1='',TXT2='';
export default class App extends Component {
state={TXT1:'',TXT2:''}
componentDidMount=()=>
{
TXT1 = require('./assets/TXT1.json');
this.setState({TXT1});
}
render() {
return (
<View style={styles.container}>
<Text>{JSON.stringify(this.state.TXT1)}</Text>
<Text>{JSON.stringify(TXT2)}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});

saveToCameraRoll is not a function

I am trying to send images which are taken using React Native Camera library to Camera Roll.
When the user presses a button the following function gets triggered:
takePicture = async function() {
if (this.camera) {
const options = { quality: 0.5, base64: true }
const data = await this.camera.takePictureAsync(options)
CameraRoll.saveToCameraRoll(data.uri)
}
}
I already know that the app sends pictures to the cache folder because after this code is executed a link to the picture is displayed:
takePicture = async function() {
if (this.camera) {
const options = { quality: 0.5, base64: true }
const data = await this.camera.takePictureAsync(options)
console.log(data.uri)
}
}
The debugger shows the following error:
Possible Unhandled Promise Rejection (id:0)
React Native Camera: TypeError: _reactNative.default.saveToCameraRoll is not a function
The code of the Cam component:
import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native'
import { RNCamera } from 'react-native-camera'
import CameraRoll from 'react-native'
import ActionButton from 'react-native-action-button'
import Icon from 'react-native-vector-icons/Ionicons'
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
button: {
height: 200,
justifyContent: 'flex-end',
alignItems: 'center'
},
actionButtonIcon: {
fontSize: 20,
height: 22,
color: 'white',
},
});
export default class Cam extends Component {
constructor() {
super()
this.takePicture = this.takePicture.bind(this)
}
takePicture = async function() {
if (this.camera) {
const options = { quality: 0.5, base64: true }
const data = await this.camera.takePictureAsync(options)
CameraRoll.saveToCameraRoll(data.uri)
}
}
render() {
return (
<View style={styles.container}>
<RNCamera
ref={ref => {this.camera = ref}}
style={{
flex: 1,
width: '100%',
position: 'relative'
}}
>
</RNCamera>
<ActionButton size={80} useNativeFeedback={false} buttonColor="rgba(231,76,60,1)">
<ActionButton.Item useNativeFeedback={false} buttonColor='#9b59b6' title="Settings" onPress={this.props.switchScreen}>
<Icon name="md-create" style={styles.actionButtonIcon} />
</ActionButton.Item>
<ActionButton.Item useNativeFeedback={false} buttonColor='#1abc9c' title="Start" onPress={this.takePicture}>
<Icon name="md-done-all" style={styles.actionButtonIcon} />
</ActionButton.Item>
</ActionButton>
</View>
)
}
}
Looking at this example of how to use CameraRoll :
import {
View,
Text,
TouchableHighlight,
Modal,
StyleSheet,
Button,
CameraRoll,
Image,
Dimensions,
ScrollView,
} from 'react-native'
You have to replace :
import CameraRoll from 'react-native';
by
import { CameraRoll } from 'react-native';
(I've put it as an answer so it can be accepted and close the question)
In your code, you can mutualise the imports like :
import React, {
Component,
} from 'react';
import {
RNCamera,
} from 'react-native-camera';
import {
CameraRoll,
StyleSheet,
View,
} from 'react-native';
import ActionButton from 'react-native-action-button';
import Icon from 'react-native-vector-icons/Ionicons';

Usage of navigator in react-native

I am new to react-native framework and learning how to use navigator. I tried to implement jump between two pages of APP. From "Boy" to "Girl" then back to "Boy".
Here is the code in APP.js:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, {Component, } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Image,
} from 'react-native';
import Boy from './Boy';
import {Navigator} from 'react-native-deprecated-custom-components';
import TabNavigator from 'react-native-tab-navigator';
export default class imooc_gp extends Component {
constructor(props){
super(props);
this.state = {
selectedTab:'tb_popular',
}
}
render() {
return (
<View style={styles.container}>
<Navigator
initialRoute = {{
title:'example',
component: Boy
}}
renderScene = {(route, navigator) =>{
let Component = route.component;
return <Component navigator = {navigator} {...route.params}/>
}}
></Navigator>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
page1 :{
flex: 1,
backgroundColor: 'red',
},
page2: {
flex: 1,
backgroundColor: 'yellow',
},
image: {
height: 22,
width: 22,
}
});
Boy.js:
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet
}from 'react-native';
import Girl from './Girl';
export default class Boy extends Component{
constructor(props){
super(props);
this.state = {
word: ''
}
}
render(){
return (
<View style = {styles.container}>
<Text style = {styles.text}> I am a boy</Text>
<Text style = {styles.text}
onPress = {()=>{
this.props.navigator.push({
title:'Girl',
component: Girl,
params:{
word: 'A Rose',
onCallBack: (word)=>{
this.setState({
word: word
})
}
}
})
}}>Send girl a Rose</Text>
<Text style = {styles.text}>{this.state.word}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'gray',
justifyContent: 'center'
},
text: {
fontSize: 20,
}
})
Girl.js:
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet
}from 'react-native';
export default class Girl extends Component{
constructor(props){
super(props);
this.state = {
}
}
render(){
return(
<View styles = {styles.container}>
<Text style = {styles.text}> I am a Girl</Text>
<Text style = {styles.text}>{this.state.word}</Text>
<Text style = {styles.text}
onPress = {()=>{
this.props.onCallBack('A box of chocolate')
this.props.navigator.pop()
}}>return chocolate</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'red',
justifyContent: 'center',
},
text: {
fontSize: 22
}
})
And I received the error message on iPhone emulator showed in the image:
I guess the error could be caused by wrong usage grammar of Navigator in different react-native version.
In my experience, I have found it more useful to use react-navigation library. This allows one to create a router files that lists all the pages that you want your app to navigate around; in your case, it could be Boy.js and Girl.js. Example given below:
import React from 'react';
import { StackNavigator } from 'react-navigation';
import { Boy, Girl } from '../app';
export const Screens = StackNavigator({
Boy: {
screen: Boy,
},
Girl: {
screen: Girl
}
});
And once you render the Screen component, Boy.js and Girl.js will each have access to the other screen via the "navigation.navigate" props.
So in your Boy component, rather than:
onPress = {()=>{
this.props.navigator.push({
title:'Girl',
component: Girl,
params:{
word: 'A Rose',
onCallBack: (word)=>{
this.setState({
word: word
})
}
}
})
You could simply write:
this.props.navigation.navigate("Girl")
All you would need to do is import the Girl component.
Hope this helps!

React-native, doubled call components

I have noticed some strange behavior in my test app. My components with "componentWillReceiveProps" function are double call. Should be call only once after button click but it's double in weird order.
I have 3 components:
Test - starting component
SetMessage - Receive props from Test and pass to Animation component
Animation - Receive props from SetMessage and dispaly
So after click button components and functions should be call like this:
Test->SetMessage(functions:reciveProps ->setMsg) then
Animation(functions: reciveProps->showMsg).
But in my case is:
Test->SetMessage(function:reciveProps) then Animation(function:reciveProps->showMsg) then
SetMessage(function: changeMsg) then
Animation(functions: reciveProps->showMsg).
I would like to know, if it is normal and fine? If not, why it happens and how to fix it?
Bellow all code and logs screen.
Index.android.js:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Navigator,
View
} from 'react-native';
import Test from './app/components/Test/Test';
export default class testApp extends Component {
render(){
return(
<View style={{flex:1}}>
<Test/>
</View>
)
}
}
AppRegistry.registerComponent('testApp', () => testApp);
Test.js:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Button,
View,
Animated,
Easing,
Switch,
} from 'react-native';
import SetMessage from '../SetMessage/SetMessage';
export default class Test extends Component{
constructor(){
super();
this.state = {
sendMsg:'plus'
}
}
change(){
if(this.state.sendMsg==='plus'){
this.setState({sendMsg:'minus'});
}else{
this.setState({
sendMsg:'minus'
});
}
console.log('Test com ')
}
render(){
return (
<View>
<Button
onPress={this.change.bind(this)}
title={'Start'}
/>
<SetMessage msg={this.state.sendMsg}/>
</View>
)
}
}
AppRegistry.registerComponent('Test', () => Test);
SetMessage.js:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Button,
View,
Animated,
Easing,
Switch,
} from 'react-native';
import Animation from '../Animation/Animation';
export default class SetMessage extends Component{
constructor(){
super();
this.state = {
test:'',
sendMsg:''
}
}
componentWillReceiveProps(nextProps){
this.setState({
test:nextProps.msg
},()=>this.setMsg());
console.log('SetMessage F - ReciveProp'+this.state.sendMsg)
}
setMsg(){
console.log('SetMessage F - Change Msg '+this.state.sendMsg);
this.setState({
sendMsg:this.state.test
})
}
render(){
return (
<View>
<Animation msg={this.state.sendMsg}/>
</View>
)
}
}
AppRegistry.registerComponent('SetMessage', () => SetMessage);
Animation.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Animated,
Easing,
Switch,
} from 'react-native';
export default class Animation extends Component{
constructor(){
super();
this.state = {
msg:'',
bottom: new Animated.Value(-50)
}
}
componentWillReceiveProps(nextProp){
console.log('Animation F - reciveProp'+this.state.msg);
this.setState({
msg:nextProp.msg
},()=>this.showMsg());
}
showMsg(){
console.log('Animation F - showMsg '+this.state.msg);
if(this.state.msg!='') {
Animated.sequence([
Animated.timing( // Animate over time
this.state.bottom, // The animated value to drive
{
toValue: 0,
duration: 500 // Animate to opacity: 1, or fully opaque
}),
Animated.delay(1000),
Animated.timing(this.state.bottom, // The animated value to drive
{
toValue: -50,
duration: 500 // Animate to opacity: 1, or fully opaque
}),
]).start();
}
}
render(){
return (
<View style={styles.mainCont}>
<Animated.View style={{
height:50,
width:100+'%',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
alignItems:'center',
justifyContent:'center',
position:'absolute',
bottom:this.state.bottom,
}}>
<Text style={styles.tekst}>{this.state.msg}</Text>
</Animated.View>
</View>
)
}
}
const styles=StyleSheet.create({
mainCont:{
flex:1,
backgroundColor:'gray'
},
container:{
height:50,
width:100+'%',
backgroundColor:'#000',
alignItems:'center',
justifyContent:'center',
position:'absolute',
bottom:0
}
});
AppRegistry.registerComponent('Animation', () => Animation);
Log screen:
Thank you.
If you check the official documentation: https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops
You will notice the statement "Note that React may call this method even if the props have not changed, so make sure to compare the current and next values...". I assume that some call to render is being made on one of the parents which makes a re-render call to be called on your Animation component. Hence the componentwillreceiveprops is being called. I always use this when using the hook above:
componentWillReceiveProps(newprops) {
if(newprops.active === this.props.active) { return }
//if they are different do some stuff
}
}

Categories

Resources