Search code examples
javascriptreactjstypescriptreact-typescriptreact-query

How do I properly use a variable as a parameter in react query when using axios.request(options)?


I have a React Query component like this:

function test () {
 const [var, setVar] = useState("")
 const options = {
    method: "GET",
    url: "https://api.themoviedb.org/3/search/tv",
    params: {
      query: var,
      page: "1",
    },
    headers: {
      accept: "application/json",
      Authorization:
        "Bearer insertAuthKey123456789",
    },
  };

 function fetchTvData(): Promise<void | ShowData> {
    return axios.request(options);
  }
 const { data} = useQuery({
    queryKey: ["tvSearchQuery", tvSearchQuery],
    queryFn: fetchTvData,
  });
  console.log(data?.data);
}

When I fetch data, it always fetches the previous query result. So if I search "foo", and then search "bar", it will return as if I passed "foo" into the query. I read the docs on passing variables into queries, however I'm not familiar how to do it when using an options object that accepts the query and passing that object into axios.request(object). Any help would be appreciated, thanks!

Here is the "un-abbreviated" version of the code in case the one above doesn't provide enough context:

import { useQuery } from "react-query";
import axios from "axios";
import { Stack, TextField, Button } from "@mui/material";
import { useForm } from "react-hook-form";
import { useState } from "react";

interface FormValues {
  tvSearch: string;
}
interface Tv {
  id: number;
}
interface ShowData {
  data: Tv[];
}

function ShowBox() {
  const [tvSearchQuery, setTvSearchQuery] = useState("");
  const form = useForm<FormValues>({
    defaultValues: {
      tvSearch: "",
    },
  });
  const { register, handleSubmit, formState } = form;
  const { errors } = formState;

  const options = {
    method: "GET",
    url: "https://api.themoviedb.org/3/search/tv",
    params: {
      query: tvSearchQuery,
      include_adult: "false",
      language: "en-US",
      page: "1",
    },
    headers: {
      accept: "application/json",
      Authorization:
        "Bearer key1234",
    },
  };
  function onSubmit(data: FormValues) {
    setTvSearchQuery(data.tvSearch);
    refetch();
  }
  function fetchTvData(): Promise<void | ShowData> {
    return axios.request(options);
  }
  function onSuccess(data: object) {
    console.log("success", data);
  }
  function onError(error: Error) {
    console.log("ERROR", error);
  }
  const { data, refetch } = useQuery({
    queryKey: ["tvSearchQuery", tvSearchQuery],
    queryFn: fetchTvData,
    refetchOnWindowFocus: false,
    enabled: false,
    onSuccess,
    onError,
  });
  console.log(data?.data);
  return (
    <form onSubmit={handleSubmit(onSubmit)} noValidate>
      <Stack spacing={2}>
        <TextField
          label="Enter a show or movie"
          type="tvSearch"
          {...register("tvSearch")}
          error={!!errors.tvSearch}
          helperText={errors.tvSearch?.message}
        />
        <Button type="submit" variant="contained">
          Search
        </Button>
      </Stack>
    </form>
  );
}

Solution

  • You have set enabled: false in useQuery. This means the query won't run by default. In onSubmit refetch is called, which will trigger the query even though it is not enabled. At this point you have called setTvSearchQuery, but that change have not taken effect yet, meaning the refetch will fetch the previous tvSearchQuery.

    The correct way to set this up is by setting enabled: true (or possibly enabled only if there is a tvSearchQuery). And also removing the refetch call.

    function onSubmit(data: FormValues) {
      setTvSearchQuery(data.tvSearch);
    }
    
    // [...]
    
    const { data } = useQuery({
      queryKey: ["tvSearchQuery", tvSearchQuery],
      queryFn: fetchTvData,
      refetchOnWindowFocus: false,
      // enabled: true is the default so the following line can be removed
      enabled: true,
      // alternatively enable the query only if there is a tvSearchQuery
      // enabled: !!tvSearchQuery 
      onSuccess,
      onError,
    });