React中Invalid Hook Call问题:模块化用户数据读取后报错
问题分析与解决方案
核心错误原因
- Hook使用违规:
getLoggedInUser是普通异步函数,却在内部调用了useStateHook。React规定Hook只能在React组件函数的顶层或者**自定义Hook(以use开头的函数)**中调用,普通函数里用Hook必然触发invalid hook call错误。 - 异步处理错误:
getLoggedInUser是async函数,直接赋值let userData = getLoggedInUser(text)得到的是Promise对象,不是实际用户数据,后续的判空逻辑完全失效。 - 导航逻辑未执行:login函数里的
() => navigation.navigate('Home', {user: userData})是个未执行的匿名函数,不会触发页面跳转。
修正方案
1. 重构数据读取函数,移除Hook
把getLoggedInUser改成纯异步工具函数,不需要用useState,直接返回查询到的用户数据:
// 数据读取文件 export default async function getLoggedInUser(name) { try { const querySnapshot = await firestore().collection('users').get(); let foundUser = null; querySnapshot.forEach(doc => { if (doc.data().name === name) { foundUser = doc; } }); return foundUser; } catch (error) { console.error(error); return null; } }
这里用
await替代.then简化异步逻辑,直接用变量存储查询结果,无需状态管理。
2. 修正login函数的异步处理与导航逻辑
因为getLoggedInUser是异步函数,需要用await获取结果,同时修正判空和导航逻辑:
const login = async (text, navigation) => { const userData = await getLoggedInUser(text); // 修正判空逻辑:用&&避免永远为true的无效判断 if (userData !== null && userData !== undefined) { navigation.navigate('Home', {user: userData}); } else { console.log('未找到对应用户'); } }
3. 确保组件内调用逻辑正确
Login组件里的Pressable onPress直接调用async的login函数即可:
// Login组件内的Pressable <Pressable style={[styles.button, styles.buttonClose]} onPress={() => login(name, navigation)} > {/* 按钮内容 */} </Pressable>
额外优化建议
如果后续需要在组件中管理用户状态,可以创建自定义Hook(必须以use开头),在Hook内部处理异步查询和状态:
// 自定义Hook示例 export function useLoggedInUser(name) { const [userData, setUserData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchUser = async () => { try { const user = await getLoggedInUser(name); setUserData(user); } catch (err) { setError(err); } finally { setLoading(false); } }; if (name) fetchUser(); }, [name]); return { userData, loading, error }; }
在Login组件中使用:
function Login({ navigation }) { const [name, onChangeNameText] = React.useState(''); // 实时查询用户(可选) // const { userData, loading } = useLoggedInUser(name); return (/* ... */); }
内容的提问来源于stack exchange,提问作者Wei Xiong
相关产品推荐
相关产品推荐

