Firebase auth().onAuthStateChanged not wait until auth().signInWithCredential finish

Viewed 939

I have login code in react native using firebase and google signin auth. So when new user sign in using google account, I set new data. And if user has signed in before, user go to main page.

My problem is when new user sign in > code start to get signInWithCredential > set new data user, before set data finish, onAuthStateChanged was detect there is change in auth and start to get user document / data. But because it's not finish yet, it throw error 'Can Not Get UID / Undefined UID'.

This is my login page code:

const _signIn = async () => {
setInitializing(true);
try {
  await GoogleSignin.hasPlayServices();
  const userInfo = await GoogleSignin.signIn();
  const credential = auth.GoogleAuthProvider.credential(
    userInfo.idToken,
    userInfo.accessToken,
  );
  await auth()
    .signInWithCredential(credential)
    .then(response => {
      const uid = response.user.uid;
      const data = {
        uid: uid,
        email: userInfo.user.email,
        fullname: userInfo.user.name,
        bio: 'Halo!! ..',
        username: uid.substring(0, 8),
      };
      const usersRef = firestore().collection('users');
      usersRef
        .doc(uid)
        .get()
        .then(firestoreDocument => {
          if (!firestoreDocument.exists) {
            usersRef
              .doc(data.uid)
              .set(data)
              .then(() => {
                setInitializing(false); return;
              })
              .catch(error => {
                setInitializing(false);
                Alert.alert(JSON.stringify(error.message));
              });
          } else {
            setInitializing(false);
            return;
          }
        })
        .catch(error => {
          Alert.alert(JSON.stringify(error.message));
          console.log('Error getting document:', error);
          return;
        });
    });
} catch (error) {
  if (error.code === statusCodes.SIGN_IN_CANCELLED) {
    setInitializing(false);
    Alert.alert('Sign in canceled');
  } else if (error.code === statusCodes.IN_PROGRESS) {
    setInitializing(false);
    Alert.alert('Signin in progress');
  } else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
    setInitializing(false);
    Alert.alert('PLAY_SERVICES_NOT_AVAILABLE');
  } else {
    setInitializing(false);
    Alert.alert(JSON.stringify(error.message));
  }
}};

And this is my index page code to check auth user:

useEffect(() => {
try {
  NetInfo.fetch().then(state => {
    if(state.isConnected === false){
      Alert.alert('No Internet Connection Detected');
      setInitializing(false);
      return;
    }
  });
  setInitializing(true);
  await auth().onAuthStateChanged(user => {
    if (user) {
      const usersRef = firestore().collection('users');
      usersRef
        .doc(user.uid)
        .get()
        .then(document => {
          const userData = document.data().uid;
          setisLogin(userData);
        })
        .then(() => {
          setInitializing(false);
        })
        .catch(error => {
          setInitializing(false);
          Alert.alert(JSON.stringify(error.message));
        });
    } else {
      setInitializing(false);
    }
  });
} catch (error) {
  Alert.alert(error);
} }, []);

How to wait auth().signInWithCredential finish? Thankyou.

1 Answers

If you need to perform more actions such read data from database or so after the user logs in, you should ideally unsubscribe from onAuthStateChanged. Essentially it won't trigger when the auth state changes (i.e. user logs in) and let you do your own custom actions. Once your processing is done, then you manually redirect the user to where the onAuthStateChange would have redirected is the user wa s logged in.

const authStateListenter = await auth().onAuthStateChanged(user => {
  //...
})


// Unsubscribe auth state observer when _signIn function runs
const _signIn = async () => {
  setInitializing(true);
  authStateListenter()
}

Calling authStateListener will disable the auth state observer. It's similar to detaching Firestore's listeners.

Related