反应天然。火基。如何等待异步函数执行?
当进入电话登录屏幕(下面的代码)时,我想立即检查(在使用效果中),用户已被授权并拥有一个帐户(在Getuser中)。验证后,导航到相应的屏幕。问题是导航需要几秒钟(因为Getuser是一个异步函数)。如何使使用效果的代码等待函数getuser完成,获取结果然后导航?
import React, { useEffect, useState, useContext, useRef } from "react";
import {
Text,
StyleSheet,
View,
TextInput,
TouchableOpacity,
} from "react-native";
import CustomButton from "../components/CustomButton";
import DataContext from "../context/DataContext";
import { app, auth, db } from "../../firebase";
import { doc, getDoc } from "firebase/firestore";
import {
FirebaseRecaptchaVerifierModal,
FirebaseRecaptchaBanner,
} from "expo-firebase-recaptcha";
import {
PhoneAuthProvider,
signInWithCredential,
onAuthStateChanged,
} from "firebase/auth";
const SignupPhoneScreen = ({ navigation }) => {
const { phone, setPhone } = useContext(DataContext);
const [phoneError, setPhoneError] = useState("");
const recaptchaVerifier = useRef(null);
const [verificationId, setVerificationId] = useState();
const [verificationCode, setVerificationCode] = useState();
const firebaseConfig = app ? app.options : undefined;
const [message, showMessage] = useState();
const attemptInvisibleVerification = false;
const [userInfo, setUserInfo] = useState({
status: "loading",
data: null,
error: null,
});
const [isSigned, setIsSigned] = useState(false);
useEffect(() => {
console.log("SignupPhoneScreen. useEffect");
const getUser = async (phoneNumber) => {
console.log("SignupPhoneScreen. useEffect. getUser");
const docRef = doc(db, "users", phoneNumber);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
console.log(
"SignupPhoneScreen. useEffect. getUser. last_name=",
docSnap.data().last_name
);
console.log(
"SignupPhoneScreen. useEffect. getUser. data=",
docSnap.data()
);
// setUserInfo({ status: "fetched", data: docSnap.data(), error: null });
navigation.navigate("MainHome");
} else {
// setUserInfo({ status: "fetched", data: null, error: null });
setPhone(phoneNumber);
navigation.navigate("SignupLanguage");
}
};
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
console.log(
"SignupPhoneScreen. useEffect. user.phoneNumber=",
user.phoneNumber
);
console.log("SignupPhoneScreen. useEffect. Before getUser", userInfo);
getUser(user.phoneNumber);
console.log("SignupPhoneScreen. useEffect. After getUser", userInfo);
}
});
return unsubscribe;
}, [isSigned]);
const sendVerification = async () => {
console.log("SignupPhoneScreen. sendVerification");
try {
const phoneProvider = new PhoneAuthProvider(auth);
const verificationId = await phoneProvider.verifyPhoneNumber(
phone,
recaptchaVerifier.current
);
setVerificationId(verificationId);
showMessage({
text: "Verification code has been sent to your phone",
});
} catch (err) {
showMessage({ text: `Error: ${err.message}`, color: "red" });
}
};
const confirmCode = async () => {
console.log("SignupPhoneScreen. confirmCode");
try {
const credential = PhoneAuthProvider.credential(
verificationId,
verificationCode
);
await signInWithCredential(auth, credential);
showMessage({ text: "Phone authentication successful" });
} catch (err) {
showMessage({ text: `Error: ${err.message}`, color: "red" });
}
};
const handleSubmit = () => {
console.log("SignupPhoneScreen. handleSubmit");
var phoneLength = phone.trim().length;
if (phoneLength == 0) {
setPhoneError("Phone is required");
} else if (phoneLength < 9) {
setPhoneError("Phone should be minimum 9 characters");
} else {
setPhoneError("");
sendVerification();
}
};
const isPhoneValid = () => {
return phoneError.length == 0;
};
const handleNavigation = () => {
console.log("SignupPhoneScreen. handleNavigation");
var user = auth.currentUser;
console.log("SignupPhoneScreen. handleNavigation. user=", user);
showMessage(undefined);
if (user) {
setIsSigned(true);
}
};
return (
<View style={styles.containerGeneral}>
<View style={styles.containerRecaptcha}>
<FirebaseRecaptchaVerifierModal
ref={recaptchaVerifier}
firebaseConfig={firebaseConfig}
// attemptInvisibleVerification
/>
</View>
<View style={styles.containerCaption}>
<Text style={styles.textCaption}>Enter your phone number</Text>
</View>
<View style={styles.containerInput}>
<TextInput
style={styles.input}
placeholder="+79999999999"
// autoFocus
keyboardType="phone-pad"
defaultValue={phone}
onChangeText={(value) => setPhone(value)}
/>
</View>
<View style={styles.containerError}>
<Text
style={[
styles.textSmall,
{ color: isPhoneValid() ? "transparent" : "red" },
]}
>
{phoneError}
</Text>
</View>
<View style={styles.containerText}>
<Text style={styles.textSmall}>
We will send an SMS to this number with a confirmation code.
</Text>
</View>
<View style={styles.containerButton}>
<CustomButton title="Send Verification Code" onPress={handleSubmit} />
</View>
<View style={styles.containerInputLabel}>
<Text style={styles.textLabel}>Enter verification code</Text>
</View>
<View style={[styles.containerInput, { marginTop: 0 }]}>
<TextInput
style={styles.input}
editable={!!verificationId}
placeholder="123456"
keyboardType="number-pad"
onChangeText={setVerificationCode}
/>
</View>
<View style={styles.containerButton}>
<CustomButton title="Confirm Verification Code" onPress={confirmCode} />
</View>
{message ? (
<TouchableOpacity
style={[
StyleSheet.absoluteFill,
{ backgroundColor: 0xffffffee, justifyContent: "center" },
]}
// onPress={() => showMessage(undefined)}
onPress={handleNavigation}
>
<Text style={[styles.textPopup, { color: message.color }]}>
{message.text}
</Text>
</TouchableOpacity>
) : undefined}
{attemptInvisibleVerification && <FirebaseRecaptchaBanner />}
</View>
);
};
export default SignupPhoneScreen;
When going to the phone login screen (its code below), I want to immediately check (in useEffect) that a user is authorized and has an account (in getUser). After that validation, navigate to the corresponding screen. The problem is that navigation takes a few seconds (because of getUser is an async function). How can I make the code in useEffect wait for function getUser to complete, get the result, and then navigate?
import React, { useEffect, useState, useContext, useRef } from "react";
import {
Text,
StyleSheet,
View,
TextInput,
TouchableOpacity,
} from "react-native";
import CustomButton from "../components/CustomButton";
import DataContext from "../context/DataContext";
import { app, auth, db } from "../../firebase";
import { doc, getDoc } from "firebase/firestore";
import {
FirebaseRecaptchaVerifierModal,
FirebaseRecaptchaBanner,
} from "expo-firebase-recaptcha";
import {
PhoneAuthProvider,
signInWithCredential,
onAuthStateChanged,
} from "firebase/auth";
const SignupPhoneScreen = ({ navigation }) => {
const { phone, setPhone } = useContext(DataContext);
const [phoneError, setPhoneError] = useState("");
const recaptchaVerifier = useRef(null);
const [verificationId, setVerificationId] = useState();
const [verificationCode, setVerificationCode] = useState();
const firebaseConfig = app ? app.options : undefined;
const [message, showMessage] = useState();
const attemptInvisibleVerification = false;
const [userInfo, setUserInfo] = useState({
status: "loading",
data: null,
error: null,
});
const [isSigned, setIsSigned] = useState(false);
useEffect(() => {
console.log("SignupPhoneScreen. useEffect");
const getUser = async (phoneNumber) => {
console.log("SignupPhoneScreen. useEffect. getUser");
const docRef = doc(db, "users", phoneNumber);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
console.log(
"SignupPhoneScreen. useEffect. getUser. last_name=",
docSnap.data().last_name
);
console.log(
"SignupPhoneScreen. useEffect. getUser. data=",
docSnap.data()
);
// setUserInfo({ status: "fetched", data: docSnap.data(), error: null });
navigation.navigate("MainHome");
} else {
// setUserInfo({ status: "fetched", data: null, error: null });
setPhone(phoneNumber);
navigation.navigate("SignupLanguage");
}
};
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
console.log(
"SignupPhoneScreen. useEffect. user.phoneNumber=",
user.phoneNumber
);
console.log("SignupPhoneScreen. useEffect. Before getUser", userInfo);
getUser(user.phoneNumber);
console.log("SignupPhoneScreen. useEffect. After getUser", userInfo);
}
});
return unsubscribe;
}, [isSigned]);
const sendVerification = async () => {
console.log("SignupPhoneScreen. sendVerification");
try {
const phoneProvider = new PhoneAuthProvider(auth);
const verificationId = await phoneProvider.verifyPhoneNumber(
phone,
recaptchaVerifier.current
);
setVerificationId(verificationId);
showMessage({
text: "Verification code has been sent to your phone",
});
} catch (err) {
showMessage({ text: `Error: ${err.message}`, color: "red" });
}
};
const confirmCode = async () => {
console.log("SignupPhoneScreen. confirmCode");
try {
const credential = PhoneAuthProvider.credential(
verificationId,
verificationCode
);
await signInWithCredential(auth, credential);
showMessage({ text: "Phone authentication successful" });
} catch (err) {
showMessage({ text: `Error: ${err.message}`, color: "red" });
}
};
const handleSubmit = () => {
console.log("SignupPhoneScreen. handleSubmit");
var phoneLength = phone.trim().length;
if (phoneLength == 0) {
setPhoneError("Phone is required");
} else if (phoneLength < 9) {
setPhoneError("Phone should be minimum 9 characters");
} else {
setPhoneError("");
sendVerification();
}
};
const isPhoneValid = () => {
return phoneError.length == 0;
};
const handleNavigation = () => {
console.log("SignupPhoneScreen. handleNavigation");
var user = auth.currentUser;
console.log("SignupPhoneScreen. handleNavigation. user=", user);
showMessage(undefined);
if (user) {
setIsSigned(true);
}
};
return (
<View style={styles.containerGeneral}>
<View style={styles.containerRecaptcha}>
<FirebaseRecaptchaVerifierModal
ref={recaptchaVerifier}
firebaseConfig={firebaseConfig}
// attemptInvisibleVerification
/>
</View>
<View style={styles.containerCaption}>
<Text style={styles.textCaption}>Enter your phone number</Text>
</View>
<View style={styles.containerInput}>
<TextInput
style={styles.input}
placeholder="+79999999999"
// autoFocus
keyboardType="phone-pad"
defaultValue={phone}
onChangeText={(value) => setPhone(value)}
/>
</View>
<View style={styles.containerError}>
<Text
style={[
styles.textSmall,
{ color: isPhoneValid() ? "transparent" : "red" },
]}
>
{phoneError}
</Text>
</View>
<View style={styles.containerText}>
<Text style={styles.textSmall}>
We will send an SMS to this number with a confirmation code.
</Text>
</View>
<View style={styles.containerButton}>
<CustomButton title="Send Verification Code" onPress={handleSubmit} />
</View>
<View style={styles.containerInputLabel}>
<Text style={styles.textLabel}>Enter verification code</Text>
</View>
<View style={[styles.containerInput, { marginTop: 0 }]}>
<TextInput
style={styles.input}
editable={!!verificationId}
placeholder="123456"
keyboardType="number-pad"
onChangeText={setVerificationCode}
/>
</View>
<View style={styles.containerButton}>
<CustomButton title="Confirm Verification Code" onPress={confirmCode} />
</View>
{message ? (
<TouchableOpacity
style={[
StyleSheet.absoluteFill,
{ backgroundColor: 0xffffffee, justifyContent: "center" },
]}
// onPress={() => showMessage(undefined)}
onPress={handleNavigation}
>
<Text style={[styles.textPopup, { color: message.color }]}>
{message.text}
</Text>
</TouchableOpacity>
) : undefined}
{attemptInvisibleVerification && <FirebaseRecaptchaBanner />}
</View>
);
};
export default SignupPhoneScreen;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以尝试添加一个加载程序,
如果用户获得授权并具有帐户,则可以添加使用效果,
最好的方法是在app.js中使用多个路由器
。
但 https://reaectnavigation.org/docs/auth-flow/“ rel =” nofollow noreferrer“> https://reactnavigation.org/docs/auth-flow/
You can try to add a loader, u can add
And then in the useEffect if the user is authorized and has an account
But the best way is to have multiple router in your App.js
You can find an example here
https://reactnavigation.org/docs/auth-flow/