trash_clam
trash_clam

Reputation: 61

Why is my React Query query function being called when it should be disabled?

I want to conditionally set the parameters and fetching function called in a React Query function (useSpeciesCodes.js) in order to fetch from one of two API endpoints (fetching functions are getSpeciesCodesByRegion or getSpeciesCodesByAddress), based off of URL query and search parameters. When the parameters and function definition are returned from another hook (useGetSpeciesCodesFunction.js), only then should the query function run.

/**
 * useSpeciesCodes.js
 */
import { useQuery } from "@tanstack/react-query";
import { useParams, useSearchParams } from "react-router-dom";
import { useGetSpeciesCodesFunction } from "./useGetSpeciesCodesFunction";

export function useSpeciesCodes() {
  const { layer } = useParams();
  const [searchParams] = useSearchParams();
  const lat = searchParams.get("lat");
  const lng = searchParams.get("lng");

  const { params, speciesCodesFunction } = useGetSpeciesCodesFunction(layer, lat, lng);

  const {
    status,
    data: speciesCodes,
    error,
  } = useQuery({
    queryKey: ["speciesCodes", params],
    queryFn: () => speciesCodesFunction(params),
    enabled: !!(params && speciesCodesFunction)
  });

  return { status, error, speciesCodes };
}
/**
 * useGetSpeciesCodesFunction.js
 */

import { useEffect, useState } from "react";
import { getSpeciesCodesByAddress, getSpeciesCodesByRegion } from "../services/apiEBird";
import { getAddressbyCoordinates } from "../services/apiRadar";
import { useParams, useSearchParams } from "react-router-dom";

export function useGetSpeciesCodesFunction() {
    const { layer } = useParams();
    const [searchParams] = useSearchParams();
    const lat = searchParams.get("lat");
    const lng = searchParams.get("lng");
    const [params, setParams] = useState(null);
    const [speciesCodesFunction, setSpeciesCodesFunction] = useState(null)

    useEffect(
        () => {
            async function handleLocation(layer, lat, lng) {
                // If layer is state or country, convert option value to ISO standardized code to get region code for eBird API
                if (layer === 'state') {
                    const { stateCode, countryCode } = await getAddressbyCoordinates(layer, lat, lng);
                    setParams(`${countryCode}-${stateCode}`)
                    setSpeciesCodesFunction(getSpeciesCodesByRegion);
                } else if (layer === 'country') {
                    const { countryCode } = await getAddressbyCoordinates(layer, lat, lng);
                    setParams(countryCode);
                    setSpeciesCodesFunction(getSpeciesCodesByRegion);
                } else {
                    const radius = 25;
                    setParams({ lat, lng, radius });
                    setSpeciesCodesFunction(getSpeciesCodesByAddress);
                }
            }
            handleLocation(layer, lat, lng);
        }
        , [layer, lat, lng]
    )
    console.log(params, speciesCodesFunction)
    return { params, speciesCodesFunction }

}

The output shows that a fetch function getSpeciesCodesByRegion is being called before the useGetSpeciesCodesFunction.js hook returns non-null values, when it should not be called because of the condition in the 'enabled' option. An additional issue/reason I am confused is why the function being returned from useGetSpeciesCodesFunction.js is a Promise and not a function definition, but it is being handled as a function definition by React Query.

1. useGetSpeciesCodesFunction.js:44 null null
2. apiRadar.js:8 getAddressbyCoordinates
3. apiEBird.js:11 getSpeciesCodesByRegion null
4. useGetSpeciesCodesFunction.js:44 US-WA Promise {<pending>}
5. useGetSpeciesCodesFunction.js:44 US-WA Promise {<fulfilled>: Array(0)}

This problem is driving me crazy. I have tried wrapping the useGetSpeciesCodesFunction async function in multiple async-await layers considering it is an asynchronous issue and moving the async function outside hooks or into other hooks. I have tried a workaround for a bug where the enabled option is reported to be not working (https://github.com/TanStack/query/issues/1196), but the query function is called anyway. Of course, I have also tried simply setting the enabled option to false and it still runs. I want useGetSpeciesCodesFunction to return parameters and a function definition, based on the URL and search params. I want useSpeciesCodes to call the function is is passed with the parameters it is passed and return data from the fetching API.

Upvotes: 0

Views: 228

Answers (1)

trash_clam
trash_clam

Reputation: 61

I discovered that the reason the API calls were being made and so making it appear that the React Query query function was being called while disabled was because the useState hook cannot store function definitions. By trying to store a function in state, it was triggering a call to the API function. The fix is simply passing a callback function to the setter: setSpeciesCodesFunction(() => getSpeciesCodesByRegion).

How to store a function with useState

Upvotes: 3

Related Questions