由于某些原因,在我的函数"login"中,我的"currentUser"State总是返回null。我要做的是在用户登录时对用户文档设置快照。
我也不确定是否可以在这样的状态下保存退订函数但这是一个问题,我还没有机会使用
我的上下文组件是这样的:
import React, { useContext, useState, useEffect } from 'react'
import { auth, db } from '../init/firebase'
const AuthContext = React.createContext()
export function useAuth() {
return useContext(AuthContext)
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState("")
const [loading, setLoading] = useState(true)
// User firebase doc init
const [userDoc, setUserDoc] = useState({
loaded: false,
data: [],
})
const [firebaseUnsubscriber, setFirebaseUnsubscriber] = useState(null);
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password)
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password).then(() => {
// The problem here is that "currentUser" is always null
const firebaseUnsubscriber = db.collection("users").doc(currentUser.uid).onSnapshot((doc) => {
setUserDoc({
loaded: true,
data: doc.data(),
})
});
setFirebaseUnsubscriber(firebaseUnsubscriber);
})
}
function logout() {
return auth.signOut().then(() => {
firebaseUnsubscriber();
})
}
useEffect(() => {
const unsubscriber = auth.onAuthStateChanged((user) => {
setCurrentUser(user)
setLoading(false)
})
return unsubscriber
}, [])
const value = {
currentUser,
userDoc,
login,
signup,
logout,
}
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
)
}
这只是时间问题。当你调用setCurrentUser
或其他从useState()
调用返回的setter时,你不改变变量的当前值——而是设置下一个变量的值——直到React决定需要渲染器时才会使用。
不要在signInWithEmailAndPassword()
的then
处理程序中使用currentUser
,而应该使用承诺中包含的UserCredential
对象。
function login(email, password) {
return auth
.signInWithEmailAndPassword(email, password)
.then((userCredential) => {
const firebaseUnsubscriber = db.collection("users")
.doc(userCredential.user.uid)
.onSnapshot((doc) => {
setUserDoc({
loaded: true,
data: doc.data(),
})
});
setFirebaseUnsubscriber(firebaseUnsubscriber);
});
}
现在,虽然上面的代码可以解决您的问题,但仍然存在许多问题:
setFirebaseUnsubscriber
在状态下存储一个退订函数,这将导致一个呈现,这意味着应该调用退订者,这导致一个新的退订者被存储,这意味着应该调用退订者,这导致…(用户数据部分应该在自己的useEffect
中)- 检索用户数据的错误被静默忽略
- 新创建的用户将没有任何用户数据要加载(并且
data
将被设置为undefined
而不是[]
,就像初始状态一样) - 退出的用户没有清除他们的数据
- 你的
currentUser
状态变量的类型是User | "" | null
。用户User | null
(建议使用loading
)或User | null | undefined
。 - 当前用户的加载状态不暴露给上下文消费者
- 当前代码利用should-be-considered-deprecated名称空间v8 Web SDK——如果编写新的代码,您应该使用模块化v9 Web SDK。
要解决这些问题的方法有点复杂,但很健壮,请查看此答案及其FirebaseAuthUserContext
版本。在撰写本文时,它使用v8 SDK,但我将在将来将其更新为v9。