从 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.authIsReady
和 state.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])
我正在尝试检索在我们看到 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.authIsReady
和 state.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])