React中如何合法在条件语句后调用Hook?解决需先获取用户ID再调用钩子的问题
问题根因
useDocumentData被放在了3个条件return分支之后,仅当用户存在、鉴权加载完成且无错误时才会被调用,不同渲染场景下Hook调用数量不一致,违反了React Hook调用规则。
方案1:拆分组件(推荐,逻辑分层清晰)
将需要使用用户数据的逻辑独立为子组件,父组件仅处理鉴权逻辑,鉴权通过后才渲染子组件,子组件内可安全调用用户相关Hook。
父组件代码
import { useAuthState } from "react-firebase-hooks/auth"; import { Redirect } from "react-router-dom"; import UserDataContent from "./UserDataContent"; function YourComponent() { // 加载用户状态 const [user, loadingAuthState, errorAuthState] = useAuthState(auth); // 用户状态加载中 if(loadingAuthState) { return <div>加载中...</div> } // 加载出现错误 else if(errorAuthState) { alert(errorAuthState); return <Redirect to="login"/> } // 用户不存在则跳转登录页 else if(!user) { return <Redirect to="/login"/> } // 鉴权通过才渲染子组件 return <UserDataContent user={user} /> }
子组件代码(UserDataContent.jsx)
import { useDocumentData } from "react-firebase-hooks/firestore"; import { doc } from "firebase/firestore"; function UserDataContent({ user }) { // Hook在组件顶层调用,此时user一定存在,符合规则 const [value, loading, error] = useDocumentData(doc(db, "users", user.uid)); // 处理用户数据加载逻辑 if(loading) return <div>用户数据加载中...</div> if(error) return <div>数据加载出错:{error.message}</div> return <div>渲染用户数据:{JSON.stringify(value)}</div> } export default UserDataContent;
方案2:不拆分组件,利用Hook参数容错特性
react-firebase-hooks的查询类Hook支持传入无效引用,会自动暂停请求不会报错,因此可以将useDocumentData提到组件最顶层,用可选参数处理user为空的情况。
import { useAuthState } from "react-firebase-hooks/auth"; import { useDocumentData } from "react-firebase-hooks/firestore"; import { doc } from "firebase/firestore"; import { Redirect } from "react-router-dom"; function YourComponent() { // 所有Hook统一放在组件最顶层 const [user, loadingAuthState, errorAuthState] = useAuthState(auth); // user不存在时传入undefined,Hook自动暂停请求 const [value, loading, error] = useDocumentData(user ? doc(db, "users", user.uid) : undefined); // 用户状态加载中 if(loadingAuthState) { return <div>加载中...</div> } // 加载出现错误 else if(errorAuthState) { alert(errorAuthState); return <Redirect to="login"/> } // 用户不存在则跳转登录页 else if(!user) { return <Redirect to="/login"/> } // 处理用户数据加载逻辑 if(loading) return <div>用户数据加载中...</div> if(error) return <div>数据加载出错:{error.message}</div> return <div>渲染用户数据:{JSON.stringify(value)}</div> }
两种方案都保留了用户加载阶段的「加载中」提示,符合React规范,优先推荐使用方案1,代码可维护性更高。
内容的提问来源于stack exchange,提问作者ArchyInUse
相关产品推荐
相关产品推荐

