react-nativeexpotanstackreact-query

problem with Hooks and Components: Error Invalid hook


I’m building a react native app using expo and I created a component called FlightList.tsx that fetches flight data using a custom hook useFlightList.tsx (which internally uses React Query’s useQuery).

When I render <FlightList /> inside my HomePage, I get this error:

Invalid hook call. Hooks can only be called inside the body of a function component. 
This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app

What I’ve checked so far: FlightList is a functional component starting with uppercase F.

These are my implementations

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 <Text>Loading flights...</Text>;
  if (isError) return <Text>Failed to load flights</Text>;

  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>
  );
}

userFLightList.ts

import { useQuery, UseQueryResult } from "@tanstack/react-query";
import {
 AssignedFlight,
 fetchAssignedFlights,
} from "../services/flightService";

export function useFlightList(): UseQueryResult<AssignedFlight[]> {
 return useQuery<AssignedFlight[]>({
   queryKey: ["flights"],
   queryFn: fetchAssignedFlights,
   enabled: true,
 });
}

home.tsx

import { Pressable, View } from "react-native";
import { useRouter } from "expo-router";
import useAuthStore from "../../stores/authStore";
import FlightList from "../../components/flights/flightList";
import React from "react";

export default function HomePage() {
  const { logout } = useAuthStore();
  const router = useRouter();
  const handleLogout = () => {
    logout();
    router.replace("/auth/login");
  };

  return (
    <View className="flex-1 p-4 bg-white">
      <FlightList />
      <Pressable onPress={handleLogout}></Pressable>
    </View>
  );
}

flightService.ts

export async function fetchAssignedFlights(): Promise<AssignedFlight[]> {
  const { getUser } = useAuthStore();
  const user = getUser();
  const response = await api.get<AssignedFlight[]>(
    `/assign/flights-by-agent/${user.id}`,
  );
  return response.data;
}

My questions:

  1. Why am I still seeing the invalid hook call error?
  2. How can I correctly use hooks like useQuery inside a nested component so it doesn’t throw this error?

Solution

  • Q1: Why am I still seeing the invalid hook call error?
    It looks like you're trying to call a React hook (useAuthStore()) within your regular async service function fetchAssignedFlights. Just a heads up, hooks are only meant to be used inside components or custom hooks. So, when React Query tries to run that function later, it ends up breaking the Rules of Hooks and throws an error.

    Q2: How can I correctly use hooks like useQuery inside a nested component so it doesn’t throw this error?
    Move all hook calls into a component or a custom hook, not into your service. One fix is to pass the userId from your hook into the service:

    // useFlightList.ts
    import { useQuery } from "@tanstack/react-query";
    import useAuthStore from "../stores/authStore";
    import { fetchAssignedFlights } from "../services/flightService";
    
    export function useFlightList() {
      const userId = useAuthStore((s) => s.getUser().id);
    
      return useQuery({
        queryKey: ["flights", userId],
        queryFn: () => fetchAssignedFlights(userId),
        enabled: !!userId,
      });
    }
    
    // flightService.ts
    export async function fetchAssignedFlights(userId: string) {
      const response = await api.get(`/assign/flights-by-agent/${userId}`);
      return response.data;
    }
    

    If you’re using Zustand, another option is to use useAuthStore.getState() in the service (that’s not a hook, so it’s safe).