React Native组件与Hooks报错:Invalid hook call排查与解决
问题解答
1. 报错原因
你在flightService.ts的fetchAssignedFlights普通异步函数里调用了useAuthStore Hook,这直接违反了React Hooks的核心规则:Hooks只能在函数组件的顶层或自定义Hook的顶层调用,绝不允许在普通函数、异步回调、循环或条件判断中调用Hook。
当useQuery执行时会调用fetchAssignedFlights,此时在这个普通函数里的Hook调用就触发了"Invalid hook call"错误。
2. 正确解决方案
步骤1:修改请求函数,移除内部Hook调用
把fetchAssignedFlights改成纯异步函数,所需的userId从外部传入:
// flightService.ts export async function fetchAssignedFlights(userId: number): Promise<AssignedFlight[]> { const response = await api.get<AssignedFlight[]>( `/assign/flights-by-agent/${userId}`, ); return response.data; }
步骤2:在自定义Hook中处理依赖参数
在useFlightList这个自定义Hook里获取用户信息,再传递给请求函数,同时优化请求触发时机:
// useFlightList.ts import { useQuery, UseQueryResult } from "@tanstack/react-query"; import { AssignedFlight, fetchAssignedFlights } from "../services/flightService"; import useAuthStore from "../stores/authStore"; export function useFlightList(): UseQueryResult<AssignedFlight[]> { const { getUser } = useAuthStore(); const user = getUser(); return useQuery<AssignedFlight[]>({ queryKey: ["flights", user.id], // 将userId加入queryKey,用户切换时自动重新请求 queryFn: () => fetchAssignedFlights(user.id), enabled: !!user?.id, // 仅当userId存在时才发起请求,避免无效调用 }); }
步骤3:清理FlightList组件冗余代码
移除重复的isLoading和isError判断:
// FlightList.tsx import { ActivityIndicator, Text, View } from "react-native"; import { useFlightList } from "../../hooks/useFlightList"; export default function FlightList() { const { data: flights, isLoading, isError, error } = useFlightList(); if (isLoading) { return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <ActivityIndicator size="large" color="#043150" /> <Text style={{ marginTop: 10 }}>Loading flights...</Text> </View> ); } if (isError) { console.error("Flight loading error:", error); return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Text style={{ color: "red" }}>Failed to load flights</Text> <Text style={{ fontSize: 12, marginTop: 5 }}> {error?.message || "Unknown error occurred"} </Text> </View> ); } return ( <View> <Text>List flights</Text> {flights && flights.length > 0 ? ( <Text>Found {flights.length} flights</Text> ) : ( <Text>No flights available</Text> )} </View> ); }
嵌套组件使用useQuery的核心要点
- 所有Hook调用必须在函数组件或自定义Hook的顶层,不能嵌套在任何代码块中
- 数据请求函数保持纯函数特性,所需依赖从外部传入,不要在内部调用Hook
- 利用
queryKey传递依赖参数,确保依赖变化时自动触发重新请求 - 通过
enabled选项控制请求时机,避免依赖未就绪时发起无效请求
内容的提问来源于stack exchange,提问作者Mohamed Amine Bejaoui
相关产品推荐
相关产品推荐

