当转到电话登录屏幕(其代码如下)时,我想立即检查(在useEffect中)用户是否被授权并拥有一个帐户(在getUser中)。验证之后,导航到相应的屏幕。问题是导航需要几秒钟(因为getUser是一个异步函数)。我如何使useEffect中的代码等待函数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;
你可以尝试添加一个加载器,你可以添加
const [isLoading, setIsLoading] = useState(false);
// The render
if (isLoading) {
return (
<Text>I'm loading</Text>
);
}
然后在useEffect中如果用户被授权并且有一个帐户
useEffect(() => {
if(user have an account) {
navigate('Screen');
} else {
// the the phone login screen can display
setIsLoading(false)
}
}, []);
但是最好的方法是在你的App.js中有多个路由器
你可以在这里找到一个例子
https://reactnavigation.org/docs/auth-flow/