I'm trying to fetch data from firestore, my workflow like this:
Create an array, then log the id of collection of 'users'
Check if user exist by check if the value exist on the above array , if exist, then login directly, if not create new collection on firestore
But don't know how when i log the data, it show correctly, but if i log the length, it always show 0, and of course the comparison show false everytime
Here is the code
export default function Login(props: LoginI) {
const user = useRef<User>();
const [userExist, setUserExist] = useState<boolean>(false);
let ListUser: any[] = [];
const {} = props;
const addNew = () => {
firestore()
.collection("Users")
.doc(user.current?.user?.email)
.set({
userInfo: { ...user.current },
note: firebase.firestore.FieldValue.arrayUnion(),
});
// .then(() => console.log("success"));
};
const getUser = async () => {
await firebase
.firestore()
.collection("Users")
.get()
.then((data) => {
data.forEach((snapshot) => {
ListUser.push(snapshot.id); ====> //add user to local array
});
});
};
async function signIn() {
// Get the users ID token
const userInfo = await GoogleSignin.signIn();
user.current = userInfo;
getUser();
console.log("firebaseList", ListUser); ==> always return value
console.log("firebaseList", ListUser.length); ==> alway return 0
// ListUser = ListUser.concat(user.current.user?.email);
ListUser.forEach((item) => {
console.log("item", item);
if (item === user.current?.user?.email) {
setUserExist(true);
return;
}
return;
});
console.log(userExist);
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(
userInfo.idToken
);
// Sign-in the user with the credential
return auth().signInWithCredential(googleCredential);
}
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Button
onPress={() => {
signIn();
}}
>
<Text style={{ color: "white" }}>Login</Text>
</Button>
</View>
);
}
I don't know where i get mess up, please help, thank you so much
CodePudding user response:
You are calling a distant database in your getUser
function (in this case, firebase
), a network request which will inevitably take longer to execute than your local code.
This leads to an issue called race condition. The code below your call to getUser()
might be executed before the network request is completed, resulting in unpredictable behavior.
To prevent this, you need to wait for the network call to complete before treating any further instructions. Whether you do it via callbacks
, promises
or async/await
syntax is up to your preferences but since you already use async/await
, you need to await
your call to getUser()
, below is your code with the correction:
export default function Login(props: LoginI) {
const user = useRef<User>();
const [userExist, setUserExist] = useState<boolean>(false);
let ListUser: any[] = [];
const {} = props;
const addNew = () => {
firestore()
.collection("Users")
.doc(user.current?.user?.email)
.set({
userInfo: { ...user.current },
note: firebase.firestore.FieldValue.arrayUnion(),
});
// .then(() => console.log("success"));
};
const getUser = async () => {
await firebase
.firestore()
.collection("Users")
.get()
.then((data) => {
data.forEach((snapshot) => {
ListUser.push(snapshot.id); ====> //add user to local array
});
});
};
async function signIn() {
// Get the users ID token
const userInfo = await GoogleSignin.signIn();
user.current = userInfo;
// the line below was missing an await
await getUser();
console.log("firebaseList", ListUser); ==> always return value
console.log("firebaseList", ListUser.length); ==> alway return 0
// ListUser = ListUser.concat(user.current.user?.email);
ListUser.forEach((item) => {
console.log("item", item);
if (item === user.current?.user?.email) {
setUserExist(true);
return;
}
return;
});
console.log(userExist);
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(
userInfo.idToken
);
// Sign-in the user with the credential
return auth().signInWithCredential(googleCredential);
}
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Button
onPress={() => {
signIn();
}}
>
<Text style={{ color: "white" }}>Login</Text>
</Button>
</View>
);
}