I just want to do simple tutorial to learn. I simply coded authorization to see alert box but I couldn't run. Also, I'm testing it in webview on browser.
Here is my code.
console.log('pressed');
console.log(this.state.mail);
console.log(this.state.password);
if (this.state.mail == 'test' && this.state.password == 123) {
console.log("successful");
}
else {
Alert.alert(
"Alert Title",
"My Alert Msg",
[
{
text: "Cancel",
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
{ text: "OK", onPress: () => console.log("OK Pressed") }
]
);
console.log("failed");
}
}```
If part works correctly. In else part 'failed' log also works correctly but alert won't work.
As far as I searched, react native alert component won't work on web browser. I tested it with my mobile phone and saw it works.
I am trying to make an alert when the user clicks back button where he will be offered with two options, Yes or No. If the user clicks "No" the user will stay on that screen and if the user presses "Yes" then, I want some different screen to be shown.
Basically I want to prevent user from going back to the previous screen and instead redirect the user to some another screen.
Here is the example useEffect code that I am trying to make this work:
useEffect(() => {
navigation.addListener('beforeRemove', (e) => {
e.preventDefault();
Alert.alert(
'Registration Process',
'Are you sure you want to cancel the registration process?',
[
{
text: 'Yes',
style: 'destructive',
// If the user confirmed, then we dispatch the action we blocked earlier
// This will continue the action that had triggered the removal of the screen
onPress: () => {
// navigation.dispatch(e.data.action);
navigation.navigate('SignUp'); // On pressing Yes, user should be shown this screen.
},
},
{text: 'No', style: 'cancel', onPress: () => {}},
],
);
});
}, [navigation]);
After running the app, when I press "Yes" I get treated with the alert box again and again.
You can create a hook and call it on backpress on when user tries to leave the page
Create a folder called hooks where your App.js is located.
Inside that create a file called useBackHandler.ts
Inside useBackHandler.ts paste this
import { useEffect } from 'react';
import { BackHandler } from 'react-native';
export function useBackHandler(handler: () => boolean) {
useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handler);
return () => BackHandler.removeEventListener('hardwareBackPress', handler);
}, [handler]);
}
Then in your RegisterScreen create a function to execute on backpress or when user wants to goBack like this
const AlertConfirmation = () => {
Alert.alert(
'Registration Process',
'Are you sure you want to cancel the registration process?',
[
{
text: 'Yes',
style: 'destructive',
onPress: () => {
navigation.navigate('ScreenOne');
},
},
{ text: 'No', style: 'cancel', onPress: () => {} },
]
);
};
I've created a Snack for you to see working example..
Check this out.
This is my code in which I tried navigation in alert and if I write Alert.alert in my code, alert won't be shown. Why?
if (results.rowsAffected > 0) {
alert('Card Add Successfully ',
[
{
text: 'OK',
onPress: () => navigation.navigate('Home')
},
],
{ cancelable: false }
);
} else alert('Failed!');
use like this:
import { Alert } from 'react-native';
...
Alert.alert('Title','Card Add Successfully ',
[
{
text: 'OK',
onPress: () => navigation.navigate('Home')
},
],
{ cancelable: false }
);
because alert is a window method and doesn't implement the prop onPress, so you need to import react native Alert in order to pass your desired function to onPress.
I'm trying to set alert function before running delete function to confirm.
Here is my code.
Now this shows alert popup with title, explanation and two buttons as I expected.
However, after showing up alert, the machine stopped for about one minute.
I can not press anything.
After that, I can press both buttons, but nothing happens - neither console.log nor delete function.
How can I fix this? thanks
import React from 'react';
import { StyleSheet, View, Text, TouchableOpacity, Alert } from 'react-native';
import CircleButton from '../elements/CircleButton';
handlePress() {
const { currentUser } = firebase.auth();
const db = firebase.firestore();
db.collection(`users/${currentUser.uid}/friends`).doc(this.state.key).delete()
.then(() => {
console.log('Deleted');
this.props.navigation.goBack();
})
.catch((error) => {
console.log(error);
});
}
...
<CircleButton
style={styles.funcButton}
onPress={()=>{
Alert.alert(
'Are you sure to delete?',
'never recover',
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'Delete', onPress: () => this.handlePress.bind(this), style: 'destructive'},
],
{ cancelable: false }
)
}}>
{'\uf1f8'}
</CircleButton>
Change
{text: 'Delete', onPress: () => this.handlePress.bind(this), style: 'destructive'},
to
{text: 'Delete', onPress: this.handlePress, style: 'destructive'},
Because
arrow functions don’t bind this.
From my observation, the Alert dialog seems built on top of the React Native app.
So it pops out everytime you call it, and doesn't to be in the render function.
The catch is it is not an async task so the code after Alert will continue to execute regardless the callback function.
The code below demonstrates a situation where the Alert dialog keeps popping out because it reads the same barcode over and over again.
(It is written in TypeScript. Just take my word, this is a valid snippet.)
import * as React from "react";
import Camera from "react-native-camera";
import { Alert } from "react-native";
export default class BarcodeScanSreen extends React.Component<any ,any> {
private _camera;
private _onBarCodeRead = e => {
if (e.type === "QR_CODE") {
Alert.alert(
"QRCode detected",
"Do you like to run the QRCode?",
[
{ text: "No", onPress: this._onNoPress },
{ text: "Yes", onPress: this._onYesPress }
],
{ cancelable: false }
);
}
};
private _onYesPress = () => { /* process the QRCode */ }
private _onNoPress = () => { /* close the alert dialog. */ }
render() {
return (
<Camera
onBarCodeRead={this._onBarCodeRead}
aspect={Camera.constants.Aspect.fill}
ref={ref => (this._camera = ref)}
>
{/* Some another somponents which on top of the camera preview... */}
</Camera>
);
}
}
Is there a way to pause the JS code and await the response from Alert?
React-native Alert doesn't stop the execution of code below it. By changing it to async function which resolves the promise on user action will work as ASYNC-Alert.
const AsyncAlert = async () => new Promise((resolve) => {
Alert.alert(
'info',
'Message',
[
{
text: 'ok',
onPress: () => {
resolve('YES');
},
},
],
{ cancelable: false },
);
});
await AsyncAlert();
Use react-native-alert-async
I've just published a package that does exactly this and permit to await for the choice of the user. It is compatible with Expo.
import AlertAsync from "react-native-alert-async";
const myAction = async () => {
const choice = await AlertAsync(
'Title',
'Message',
[
{text: 'Yes', onPress: () => 'yes'},
{text: 'No', onPress: () => Promise.resolve('no')},
],
{
cancelable: true,
onDismiss: () => 'no',
},
);
if (choice === 'yes') {
doSomething();
}
else {
doSomethingElse();
}
}
Original answer: I've made a PR to ReactNative for this feature: https://github.com/facebook/react-native/pull/20312
Here's a simple solution.
The trick used here is to make a function that calls the button's onPress function, then resolve the promise with the index of the button. Note that this requires the alert to be uncancellable.
showAsyncAlert = (title, message, buttons, options) => {
return new Promise((resolve, reject) => {
// We can't detect a cancellation, so make sure the Alert is not cancellable.
options.cancellable = false
buttons.forEach((button, index) => {
let onPress = button.onPress
button.onPress = option => {
if (onPress) {
onPress(option)
}
resolve(index)
}
})
Alert.alert(title, message, buttons, options)
})
}
Usage:
let option = await showAsyncAlert(title, message, buttons options)
if (option === 0) {
foo()
} else {
bar()
}
Alert does not pause the code. In this case JS is not the only problem - the Camera component also keeps running in the background which is native and it will trigger the onBarCodeRead listener, regardless if the Alert is present or not.
You could try to stop the camera at the beginning on _onBarCodeRead with the stopPreview() method mentioned in the docs.
Also note that react-native-camera is currently in a migration process from Camera (RCTCamera) to RNCamera and in the new RNCamera I don't see a stopPreview() method. Anyhow, a simple flag would also do the job.
I have some workaround for this,If you have alert function like below
Alert.alert(
'Delete comment?',
'Are you sure you want to delete this comment?',
[
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{ text: 'yes', onPress:() => this.props.deleteComment(commentId),
],
{ cancelable: false },
);
//call after comment is deleted
refreshPage();
This code does not wait for alert's response, it will execute refreshPage() immediately.
so, you can do something like
Alert.alert(
'Delete comment?',
'Are you sure you want to delete this comment?',
[
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{ text: 'yes', onPress: async () => {await this.props.deleteComment(commentId);refreshPage();},
],
{ cancelable: false },
);
If you need to return a promise:
const asyncAlert = (title, message, callback) => (new Promise((resolve) => {
Alert.alert(
title,
message,
[{ text: "Cancel" }, { text: "OK", onPress: () => resolve() }], { cancelable: false }
);
}).then(callback));
Usage:
return asyncAlert("My Title", "Are you sure?", () => SOME_PROMISE_FUNCTION())