从 Firestore 检索 UseEffect 中的无限循环

Infinte loop in UseEffect retrieval from Firestore

我正在尝试检索在我们看到 Firebase Auth 具有正确的用户 uid 后登录的组织的文档。但是,我在该检索的 useEffect 函数中遇到了无限循环。

import { createContext, useEffect, useReducer} from 'react'
import { projectAuth, projectFirestore } from '../firebase'

export const AuthContext = createContext()

export const authReducer = (state, action) => {
    switch (action.type) {
        case 'LOGIN':
            return { ...state, user: action.payload }
        case 'LOGOUT':
            return { ...state, user: null }
        case 'AUTH_IS_READY':
            return { ...state, user: action.payload, authIsReady: true}
        case 'RETRIVED_ORG':
            return { ...state, org: action.payload }
        default:
            return state
    }
}

export const AuthContextProvider = ({ children }) => {
    const [state, dispatch] = useReducer(authReducer, {
        user: null,
        org: null,
        authIsReady: false
    })

    useEffect(() => {
        const unsub = projectAuth.onAuthStateChanged((user) => {
            dispatch({ type: 'AUTH_IS_READY', payload: user})
            unsub()
        })
    }, [])
    console.log('AuthContext state:', state)

    useEffect(() => {
        if (state.authIsReady) {
            projectFirestore.collection('orgs').doc(state.user.uid).get()
            .then(snapshot => {
                dispatch({ type: 'RETRIVED_ORG', payload: snapshot.data()})
            })
        }
    }, [state])

    return (
        <AuthContext.Provider value={{ ...state, dispatch }}>
            {children}
        </AuthContext.Provider>
    )
}

这是 Auth 的上下文。如您所见,第一个 useEffect 是 运行 一次,当它完成时,它会触发调度并从 reducer 将用户和 'authIsReady' 状态设置为 true。

对于第二个 useEffect,我想在 authIsReady 状态为真时 运行 它,因为只有到那时,我才会知道我有 user.uid。这确实会触发并使用调度并设置组织,但它 运行ning 多次。我认为这是因为我在第二个参数中包含 [state],但如果我删除它,我会收到一条错误消息: “React Hook useEffect 缺少依赖项:'state.authIsReady' 和 'state.user.uid'。要么包含它们,要么删除依赖项数组”。

有没有更优雅的方法?

您的第二个 useEffect 需要仅依赖于 state.authIsReadystate.user.uid。现在它在每个状态更新中触发,当你做 dispatch({ type: 'RETRIVED_ORG', payload: snapshot.data()}) 你更新 state,它再次触发第二个 useEffect,再次获取,再次更新,这就是创建无限循环。

应该是:

 useEffect(() => {
        if (state.authIsReady) {
            projectFirestore.collection('orgs').doc(state.user.uid).get()
            .then(snapshot => {
                dispatch({ type: 'RETRIVED_ORG', payload: snapshot.data()})
            })
        }
    }, [state.authIsReady, state.user.uid])