My aim is to listen the event for Android homeback button, and then give a toast when continuous click. Here the third component "react-native-easy-toast" is used, fully code snippets shown as below:
import React, { Component } from 'react';
import {View, WebView, Platform, BackHandler, StyleSheet} from 'react-native';
import Toast, {DURATION} from 'react-native-easy-toast';
export default class HomeScreen extends Component {
constructor (props) {
super(props);
}
onNavigationStateChange = (event) => {
this.setState({
navCanGoBack : event.canGoBack,
});
};
componentDidMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.onHomeBackPress);
}
}
onHomeBackPress = () => {
if (this.state.navCanGoBack) {
this.refs['webview'].goBack();
return true;
} else {
//exit app if exceed 2 seconds
if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
return false;
}
this.lastBackPressed = Date.now();
this.refs.toast.show('weill exit app press again');
return true;
}
};
render() {
return (
<View style={{flex:1}}>
<WebView
source={{ uri: 'http://www.test.com/' }}
style={{ width: '100%', height: '100%' }}
ref="webview"
onNavigationStateChange={this.onNavigationStateChange}
/>
<Toast ref="toast" />
</View>
);
}
}
Finally, run the app and error given:
undefined is not an object(evaluating '_this.refs.toast.show')
I am newer to React Native.
Please try
//inside constructor
this.toastRef = React.createRef();
...
<Toast ref={this.toastRef} />
and replace
this.refs.toast.show('weill exit app press again');
to
this.toastRef.current.show('weill exit app press again');
Related
I am learning react native from Udemy. In one of the lessons I saw AppLoading has been used for loading fonts.
So i want to learn about it in documentation from here. I am able to use that without any issues even though, I saw here that startAsync has been deprecated.
What is the alternative to this startAsync if it stopped working?
below is the code from documentation,
import React from 'react';
import { Image, Text, View } from 'react-native';
import { Asset } from 'expo-asset';
import AppLoading from 'expo-app-loading';
export default class App extends React.Component {
state = {
isReady: false,
};
render() {
if (!this.state.isReady) {
return (
<AppLoading
startAsync={this._cacheResourcesAsync}
onFinish={() => this.setState({ isReady: true })}
onError={console.warn}
/>
); }
return (
<View style={{ flex: 1 }}>
<Image source={require('./assets/snack-icon.png')} />
</View>
);
}
async _cacheResourcesAsync() {
const images = [require('./assets/snack-icon.png')];
const cacheImages = images.map(image => {
return Asset.fromModule(image).downloadAsync();
});
return Promise.all(cacheImages);
}
}
Call _cacheResourcesAsync function in componentDidMount and when all promised are resolved set state isReady to true like:
import React from 'react';
import { Image, Text, View } from 'react-native';
import { Asset } from 'expo-asset';
import AppLoading from 'expo-app-loading';
export default class App extends React.Component {
state = {
isReady: false,
};
componentDidMount(){
_cacheResourcesAsync();
}
render() {
if (!this.state.isReady) {
return (
<AppLoading />
); }
return (
<View style={{ flex: 1 }}>
<Image source={require('./assets/snack-icon.png')} />
</View>
);
}
_cacheResourcesAsync() {
const images = [require('./assets/snack-icon.png')];
const cacheImages = images.map(image => {
return Asset.fromModule(image).downloadAsync();
});
Promise.all(cacheImages).then(()=>{
this.setState({ isReady : true });
});
}
}
You should use a hook to load your images.
First, create a hook to load resources in a separate file:
import * as SplashScreen from 'expo-splash-screen';
import { useEffect, useState } from 'react';
export default function useCachedResources() {
const [isLoadingComplete, setLoadingComplete] = useState(false);
// Load any resources or data that we need prior to rendering the app
useEffect(() => {
async function loadResourcesAndDataAsync() {
try {
SplashScreen.preventAutoHideAsync();
// Load images
const images = [require('./assets/snack-icon.png')];
await images.map(async image =>
await Asset.fromModule(image).downloadAsync());
} catch (e) {
// We might want to provide this error information to an error reporting service
console.warn(e);
} finally {
setLoadingComplete(true);
SplashScreen.hideAsync();
}
}
loadResourcesAndDataAsync();
}, []);
return isLoadingComplete;
}
Then call it in your App component - I changed it to a function component, because hooks don't work in classes and it is now the recommended way of coding react:
import { Image, View } from 'react-native';
import useCachedResources from "./hooks/useCachedResources";
export default function App() {
const isLoadingComplete = useCachedResources();
if (!isLoadingComplete) {
return null;
}
return (
<View style={{ flex: 1 }}>
<Image source={require('./assets/snack-icon.png')} />
</View>
);
}
I would like to set up a scan for EAN13 codes, I am using the react-native-camera package but I ran into a **
TypeError: undefined is not an object (evaluating
'_reactNativeCamera.Camera.constants')
** and I will like your help to find out where is the error in my code.
If you can guide me, help me, that would be great, thank you very much.
import React, { Component } from 'react';
import {
Text,
View,
Alert,
TouchableOpacity,
Image
} from 'react-native';
import {Camera} from 'react-native-camera';
import styles from '../../../assets/styles'
export default class Ean13 extends Component {
constructor(props) {
super(props);
this.handleTourch = this.handleTourch.bind(this);
this.state = {
torchOn: false
}
}
onBarCodeRead = (e) => {
Alert.alert("Barcode value is" + e.data, "Barcode type is" + e.type);
}
render() {
return (
<View style={styles.container}>
<Camera
style={styles.preview}
torchMode={this.state.torchOn ? Camera.constants.TorchMode.on : Camera.constants.TorchMode.off}
onBarCodeRead={this.onBarCodeRead}
ref={cam => this.camera = cam}
aspect={Camera.constants.Aspect.fill}
>
<Text style={{
backgroundColor: 'white'
}}>BARCODE SCANNER</Text>
</Camera>
<View style={styles.bottomOverlay}>
<TouchableOpacity onPress={() => this.handleTourch(this.state.torchOn)}>
<Image style={styles.cameraIcon}
source={this.state.torchOn === true ? require('../../../assets/images/flash.png') : require('../../../assets/images/no-flash.png')} />
</TouchableOpacity>
</View>
</View>
)
}
handleTourch(value) {
if (value === true) {
this.setState({ torchOn: false });
} else {
this.setState({ torchOn: true });
}
}
}
You have used Camera
this should be RNCamera
import { RNCamera } from 'react-native-camera';
And read the constants from
RNCamera.constants.TorchMode.on
Check the docs
https://github.com/react-native-camera/react-native-camera/blob/master/docs/RNCamera.md
I am using react native and i have problem in navigating between pages in my webview because it keeps on closing whenever I pressed the back button. I tried this one and an error comes when i press the back button undefined is not an object (evaluating 'this.props.navigation.goback') Can someone help me? Thank you
import React, { Component } from 'react';
import { WebView } from 'react-native-webview';
import { BackHandler } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props)
this.handleBackButtonClick = this.handleBackButtonClick.bind(this);
}
componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButtonClick);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButtonClick);
}
handleBackButtonClick() {
this.props.navigation.goBack(null);
return true;
}
render(){
return (
<WebView
style={{ marginTop: 0 }}
source={{ uri: 'https://www.youtube.com' }}
/>
);
}
}
This code works
import React, { Component } from 'react';
import { WebView } from 'react-native-webview';
import { BackHandler } from 'react-native';
export default class App extends Component {
webView = {
canGoBack: false,
ref: null,
}
onAndroidBackPress = () => {
if (this.webView.canGoBack && this.webView.ref) {
this.webView.ref.goBack();
return true;
}
return false;
}
componentWillMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this.onAndroidBackPress);
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackHandler.removeEventListener('hardwareBackPress');
}
}
render(){
return (
<WebView
style={{ marginTop: 0 }}
source={{ uri: 'https://www.youtube.com' }}
useWebKit={true}
ref={(webView) => { this.webView.ref = webView; }}
onNavigationStateChange={(navState) => { this.webView.canGoBack = navState.canGoBack; }}
/>
);
}
}
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.
I'm building an app on codeHS that utilizes an accelerometer.
I tried dragging and dropping the accelerometer component the website provides into the code I was writing just to see how the component would work.
When I tried to run the code the debugger gave me an error, stating that it couldn't read the addListener event, stating that it was undefined. What is causing the error? I appreciate any insight or tips.
Here is a copy of the code:
import React, { Component } from 'react';
import { AppRegistry, Text, View, Listener, StyleSheet, TouchableOpacity } from 'react-native';
import { Constants, Accelerometer } from 'expo';
export default class App extends Component {
componentWillUnmount() {
this._unsubscribeFromAccelerometer();
}
componentDidMount() {
this._subscribeToAccelerometer();
}
state = {
accelerometerData: { x: 0, y: 0, z: 0 }
};
_subscribeToAccelerometer = () => {
this._acceleroMeterSubscription = Accelerometer.addListener(accelerometerData =>
this.setState({ accelerometerData })
);
};
_unsubscribeFromAccelerometer = () => {
this._acceleroMeterSubscription && this._acceleroMeterSubscription.remove();
this._acceleroMeterSubscription = null;
};
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
<Text>
Accelerometer:
x = {this.state.accelerometerData.x.toFixed(2)}{', '}
y = {this.state.accelerometerData.y.toFixed(2)}{', '}
z = {this.state.accelerometerData.z.toFixed(2)}
</Text>
</Text>
</View>
);
}
}