React useAuth结合Firestore路由首次加载读取次数异常求助
Firestore首次加载读取次数超标问题排查建议
问题描述
我在Firestore控制台发现,应用首次加载时的读取次数远超预期(预期1次,实际消耗9次),推测某些内容渲染次数超标。尝试在访问Firestore时加console.log,但没找到问题。作为React新手,查了很多帖子和文档还是搞不懂,求建议。
相关代码
index.js
const root = ReactDOM.createRoot(document.getElementById('root')) root.render( <StrictMode> <BrowserRouter> <AuthProvider> <App /> </AuthProvider> </BrowserRouter> </StrictMode> )
userContext.js
const AuthContext = createContext() async function logIn(email, password) { await signInWithEmailAndPassword(auth, email, password) } async function logOut() { await signOut(auth) } async function register(email, password) { return createUserWithEmailAndPassword(auth, email, password) } export function AuthProvider({ children }) { const [userData, setUserData] = useState(null) useEffect(() => { const unsubscribe = onAuthStateChanged(auth, async (authUser) => { if (authUser) { try { const docRef = doc(db, 'USERS', authUser.uid) const docSnap = await getDoc(docRef) const data = docSnap.data() setUserData(data) } catch (error) { console.error(error) } } else { setUserData(null) } }) return () => unsubscribe() }, []) const authContextValue = { userData, logIn, logOut, register, } return ( <AuthContext.Provider value={authContextValue}> {children} </AuthContext.Provider> ) } export function useAuth() { const context = useContext(AuthContext) if (!context) { throw new Error('No context provider') } return context }
App.js
export default function App() { const { userData } = useAuth() return ( <> {userData ? ( <Routes> <Route path="/" element={ <> <AppNavbar /> <Outlet /> </> }> <Route path="page1" element={<Page1/>} /> <Route path="page2" element={<Page2/>} /> </Route> </Routes> ) : ( <Routes> <Route path="login" element={<Login />} /> <Route path="register" element={<Register />} /> </Routes> )} </> ) }
排查与解决建议
React StrictMode的双重执行:开发环境下,
<StrictMode>会重复执行Effect和生命周期函数,包括你onAuthStateChanged里的getDoc请求,直接导致读取次数翻倍甚至多次触发。可以先注释掉<StrictMode>测试,生产环境StrictMode不会有这个问题,若要开发时避免就直接移除。避免重复获取用户数据:
onAuthStateChanged在Auth状态初始化过程中可能多次回调,比如从null到authUser的过程。可以加判断逻辑,只有当用户数据未加载或用户ID不匹配时才请求Firestore:useEffect(() => { const unsubscribe = onAuthStateChanged(auth, async (authUser) => { if (authUser) { // 仅当userData为空或uid不匹配时才发起请求 if (!userData || userData.uid !== authUser.uid) { try { const docRef = doc(db, 'USERS', authUser.uid) const docSnap = await getDoc(docRef) const data = docSnap.data() setUserData({...data, uid: authUser.uid}) // 存入uid用于后续判断 } catch (error) { console.error(error) } } } else { setUserData(null) } }) return () => unsubscribe() }, [userData]) // 添加userData作为依赖,确保判断逻辑生效缓存Context值避免重复渲染:当前
authContextValue每次都会创建新对象,导致订阅useAuth的组件重复渲染。用useMemo缓存这个对象:const authContextValue = useMemo(() => ({ userData, logIn, logOut, register, }), [userData]) // 仅当userData变化时更新对象引用查看Firestore控制台详情:直接去Firestore控制台的「使用情况」板块,查看每一条读取请求的具体路径和调用栈,精准定位重复请求的来源,比console.log更高效。
内容的提问来源于stack exchange,提问作者jose m ruiz
相关产品推荐
相关产品推荐

