useEffect触发异步Promise反复重渲染问题求助
解决React中currentUser无限循环打印及依赖警告问题
问题分析
- 无限循环根源:你的
useEffect将currentUser加入了依赖数组,每次调用setCurrentUser更新状态后,currentUser变化会触发useEffect重新执行,重新订阅auth.onAuthStateChanged;而订阅内的onSnapshot又会再次调用setCurrentUser,形成闭环循环。 - 隐藏bug:
createUserProfileDocument中userRef.get()是异步操作,你没加await,导致snapShot是Promise对象,!snapShot.exists始终为true,会重复执行用户创建逻辑。 - 依赖警告:移除
currentUser依赖后出现警告,是因为React检测到useEffect内有console.log(currentUser),但实际上这里打印的是旧状态值,没有实际意义。
解决方案
1. 修复createUserProfileDocument的异步问题
修改函数中获取快照的代码,添加await以获取实际快照对象:
export const createUserProfileDocument = async (userAuth, additionalData) => { if (!userAuth) return; const userRef = firestore.doc(`users/${userAuth.uid}`); // 添加await,获取实际的快照对象 const snapShot = await userRef.get(); console.log(snapShot); if (!snapShot.exists) { const { displayName, email } = userAuth; const createdAt = new Date(); try { await userRef.set({ displayName, email, createdAt, ...additionalData }) } catch (error) { console.log('error creating user', error.message); } } return userRef; }
2. 修复useEffect的无限循环与依赖警告
调整useEffect逻辑,仅在组件挂载时订阅一次,移除currentUser依赖,并将状态打印逻辑拆分到单独的useEffect中:
const [currentUser, setCurrentUser] = useState(null); const unSubscribeFromAuth = useRef(null); // 仅在组件挂载时订阅auth状态 useEffect(() => { unSubscribeFromAuth.current = auth.onAuthStateChanged(async userAuth => { if (userAuth) { const userRef = await createUserProfileDocument(userAuth); userRef.onSnapshot(snapShot => { setCurrentUser({ id: snapShot.id, ...snapShot.data() }) }) } else { setCurrentUser(userAuth); } }) return () => { unSubscribeFromAuth.current(); }; // 空依赖数组,确保只执行一次 }, []); // 单独监听currentUser变化,打印最新状态 useEffect(() => { console.log(currentUser); }, [currentUser]);
若不想添加额外useEffect,也可直接忽略依赖警告(不推荐但可行),在useEffect末尾添加注释:
useEffect(() => { // ... 原有代码 }, []); // eslint-disable-next-line react-hooks/exhaustive-deps
内容的提问来源于stack exchange,提问作者Narendra Singh
相关产品推荐
相关产品推荐

