Pedro Henrique
Pedro Henrique

Reputation: 127

Why is this asynchronous function being called twice

I am trying to create a user with email and password using firebase, but when I call the function that creates it, it is called twice and I get an error because I am trying to register the email that is already in use.

I noticed that the console.log('CALLED') is called once, I don't understand why RegisterWithEmail is called twice. My auth flow only creates the userDocument in the confirmation phase, for this reason userSnap.length equals zero in the second call and tries to create again.

How can I call this function once?

FILE: emailconfirm.page.tsx

registerEmail = async data => {
    const { setRegStatus, createDoc } = this.props;
    console.log('CALLED')
    await RegisterWithEmail(data).then(res => {
      console.log('Final response ', res)
      if(res === 'EMAIL_VERIFIED') {
        createDoc()
        setRegStatus({ status: 'created', data: res })
      }
      else if(res === 'SOMETHING_WENT_WRONG'){
        setRegStatus({ status: 'error', data: res })
      }

    }).catch(err => {
      console.log('Error ', err)
      setRegStatus({ status: 'error', data: err })
    })
  }

FILE: firebase.utils.tsx

export const RegisterWithEmail = async user => {
  console.log("Called Once...");

  if(!user) return 'SOMETHING_WENT_WRONG';
  else {
    const snap = await firestore.collection('users').where('email', '==', user.email).get();
    const docs = snap.docs.map((doc) => doc.data());

    if (docs.length !== 0) return 'EMAIL_HAS_ALREADY_BEEN_TAKEN';

    try {
      console.log("Trying to register email...");
      return await auth.createUserWithEmailAndPassword(user.email, user.password).then(async usr => {
        await usr.user.updateProfile({
          displayName: user.name
        }) // SETTING NAME

        const sendVerifyEmail = usr.user.sendEmailVerification().then(() => setTimer(usr.user, 5))

        return await sendVerifyEmail.then(msg => {
          console.log('Finishing...', msg)
          if(msg.txt !== 'waiting') {
            if(msg.error) {
              throw msg.txt
            }
            else return msg.txt
          }
        }).catch(() => {
          throw 'EMAIL_NOT_SENT'
        })
      }).catch(() => {
        throw 'USER_NOT_CREATED'
      })
    } catch (err) {
      throw 'USER_ALREADY_REGISTERED'
    }
  }
}

Developer console: enter image description here

Upvotes: 0

Views: 1340

Answers (2)

A Ralkov
A Ralkov

Reputation: 1044

I need more code to be sure, but I think you should add await

registerEmail = async data => {
    console.log('CALLED')
    await RegisterWithEmail(data)
}

Upvotes: 0

AKX
AKX

Reputation: 168863

You shouldn't be mixing and matching .then()s in async functions for your own sanity's sake.

Something like

export const RegisterWithEmail = async (user) => {
  if (!user) return false;
  const snap = await firestore.collection("users").where("email", "==", user.email).get();
  const docs = snap.docs.map((doc) => doc.data());
  if (docs.length !== 0) return false;
  console.log("Trying to register email...");
  try {
    const resp = await auth.createUserWithEmailAndPassword(user.email, user.password);
    // then ...
    return true;
  } catch (err) {
    // catch ...
  }
};

might work better for you.

Upvotes: 1

Related Questions