onAuthStateChanged调用太早



我想用一些额外的数据创建一个新用户(例如:subscribeToEmail字段等(。根据我在网上阅读的内容,实现这一点的方法是对用户进行身份验证(例如:使用createUserWithEmailAndPassword(,然后使用从中获得的uid在用户集合中创建新文档。这就是我下面要做的:

const handleSignup = async (formData) => {
const {email, password, ...otherUserData} = formData;
const {user} = await auth.createUserWithEmailAndPassword(email,  password);
console.log("generating user doc at signup...");
await generateUserDocument(user, otherUserData); // creates user doc (called 2nd)
}

generateUserDocument将使用从createUserWithEmailAndPassword函数调用中获得的user的uid在users集合中创建一个用户文档(如果它还不存在(。我还设置了一个身份验证状态更改事件处理程序:

auth.onAuthStateChanged(async (userAuth) => { // get the current user 
if (userAuth) {
const user = await generateUserDocument(userAuth); // user (should) already exists, so generateUserDocument will fetch the user rather than creating a new user doc, but this doesn't happen, as it is called 1st and not 2nd
dispatch(login(user)); // login logic
} else {
dispatch(logout());
}
});

这里的问题是,当我调用createUserWithEmailAndPassword时,onAuthStateChanged回调触发器,然后在我实际在handleSignup方法中创建了一个带有generateUserDocument(user, otherUserData);的用户文档之前调用generateUserDocument。换句话说,在实际创建用户之前,调用.onAuthStateChange()内部的获取用户方法generateUserDocument,这是由handleSignup方法内部的generateUserDocument完成的。因此,我在authStateChange中获取的用户数据不包括我想要的详细信息。

有没有办法解决这个问题,以便在执行onAuthStateChange事件处理程序之前(而不是之后(调用auth.createuserWithEmailAndPassword()之后的函数调用?我可能已经考虑过使用.onSnapshot()之类的东西,但我认为这可能有点过头了,因为用户数据表也不应该一直被监听,因为它很少会改变。最好有一个在onAuthStateChanged之前调用的生命周期方法,我可以使用它来填充我的用户集合,但我还没能找到太多关于它的信息。

作为参考,我一直在关注这篇关于将附加用户数据与身份验证用户记录关联的文章。

有没有办法解决这个问题,以便我的函数在auth.createuserWithEmailAndPassword()在执行onAuthStateChange事件处理程序(而不是之后(?

不,没有开箱即用的方法,因为

  1. 使用createuserWithEmailAndPassword()成功创建用户帐户后,用户也将登录到您的应用程序(请参阅文档(,并且
  2. onAuthStateChange()观察器在登录或注销时被触发

因此,在继续操作之前,确实需要等待用户Firestore文档创建完成。在我看来,最好的方法是您提到的方法,即设置user文档的侦听器。

您可以在第一次从用户文档中获取数据后立即取消侦听器,如下所示。这样,用户文档就不会被持续地监听。

auth.onAuthStateChanged((userAuth) => {    // No more need to be async
// get the current user
if (userAuth) {
const userDocRef = firestore.collection('users').doc(userAuth.uid);
const listener = userDocRef.onSnapshot((doc) => {
if (doc.exists) {
console.log(doc.data());
// Do any other action you need with the user's doc data
listener();   // Calling the unsubscribe function that cancels the listener
dispatch(login(user));
}
});
} else {
dispatch(logout());
}
});

另一种方法可以是使用可调用云函数,该函数在后端创建Auth服务中的用户和Firestore中的文档。您的handleSignup函数如下:

const handleSignup = async (formData) => {
const createUser = firebase.functions().httpsCallable('createUser');
await createUser({formData});
// The user is created in the Auth service
// and the user doc is created in Firestore
// We then need to signin the user, since the call to the Cloud Function did not do it!
const {email, password, ...otherUserData} = formData;
await auth.signInWithEmailAndPassword(email, password);
// The onAuthStateChanged listener is triggered and the Firestore doc does exist
}

最新更新