You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-Query为何返回上一次搜索数据?求助排查问题

问题原因与修复方案

核心问题

  1. React Query 缓存未区分不同搜索请求:你的queryKey固定为"tv-results",React Query会基于这个key缓存请求结果。当搜索关键词变化时,queryKey没有同步更新,导致React Query直接复用了旧的缓存数据。
  2. 异步状态更新导致请求参数滞后:onSubmit中先调用setTvSearchQuery再执行refetch,但React的setState是异步操作,此时tvSearchQuery还没更新为新的搜索词,请求依然使用旧参数发起。
  3. 请求配置未动态绑定最新参数:options定义在组件顶层,虽然每次渲染会重新创建,但fetchTvData直接引用该配置,无法确保每次请求都使用最新的搜索关键词。

修复步骤

1. 给queryKey添加搜索关键词标识

将tvSearchQuery加入queryKey,让React Query为不同的搜索词维护独立缓存:

const { data, refetch } = useQuery({
  queryKey: ["tv-results", tvSearchQuery], // 加入搜索词,区分不同请求
  queryFn: fetchTvData,
  refetchOnWindowFocus: false,
  enabled: false,
  onSuccess,
  onError,
});

2. 避免依赖异步状态更新传递参数

提取基础请求配置并修改fetchTvData,让它直接接收搜索词参数,彻底规避setState异步的问题:

// 提取基础配置,避免重复创建
const baseOptions = {
  method: "GET",
  url: "https://api.themoviedb.org/3/search/tv",
  params: {
    include_adult: "false",
    language: "en-US",
    page: "1",
  },
  headers: {
    accept: "application/json",
    Authorization: "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJmNzNkMDE0YzkzNDQ5OTQxNThkZjNlNWQ0MWVjZGY1NCIsInN1YiI6IjY0ZTQ2NzlhMWZlYWMxMDBjNDZjMWUyNCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.quqnVGOyEV10UKyr4PCb39i6JpkdKtvX4kDSoIq9gss",
  },
};

function fetchTvData(searchQuery: string): Promise<void | ShowData> {
  return axios.request({
    ...baseOptions,
    params: {
      ...baseOptions.params,
      query: searchQuery,
    },
  });
}

然后更新onSubmit和useQuery的queryFn,确保使用最新的搜索词:

function onSubmit(data: FormValues) {
  const searchTerm = data.tvSearch;
  setTvSearchQuery(searchTerm);
  refetch(); // 此时queryKey已更新,React Query会触发新请求
}

// useQuery中的queryFn同步使用tvSearchQuery
const { data, refetch } = useQuery({
  queryKey: ["tv-results", tvSearchQuery],
  queryFn: () => fetchTvData(tvSearchQuery),
  // 其余配置不变
});

3. 修正TextField的type属性

你之前的TextField使用了非标准的type="tvSearch",这会导致浏览器解析异常,改成标准的type="text":

<TextField
  label="Enter a show or movie"
  type="text"
  {...register("tvSearch")}
  error={!!errors.tvSearch}
  helperText={errors.tvSearch?.message}
/>

完整修复代码

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[];
}

const baseOptions = {
  method: "GET",
  url: "https://api.themoviedb.org/3/search/tv",
  params: {
    include_adult: "false",
    language: "en-US",
    page: "1",
  },
  headers: {
    accept: "application/json",
    Authorization: "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJmNzNkMDE0YzkzNDQ5OTQxNThkZjNlNWQ0MWVjZGY1NCIsInN1YiI6IjY0ZTQ2NzlhMWZlYWMxMDBjNDZjMWUyNCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.quqnVGOyEV10UKyr4PCb39i6JpkdKtvX4kDSoIq9gss",
  },
};

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

  function fetchTvData(searchQuery: string): Promise<void | ShowData> {
    return axios.request({
      ...baseOptions,
      params: {
        ...baseOptions.params,
        query: searchQuery,
      },
    });
  }

  function onSuccess(data: object) {
    console.log("success", data);
  }

  function onError(error: Error) {
    console.log("ERROR", error);
  }

  const { data, refetch } = useQuery({
    queryKey: ["tv-results", tvSearchQuery],
    queryFn: () => fetchTvData(tvSearchQuery),
    refetchOnWindowFocus: false,
    enabled: false,
    onSuccess,
    onError,
  });

  function onSubmit(data: FormValues) {
    const searchTerm = data.tvSearch;
    setTvSearchQuery(searchTerm);
    refetch();
  }

  console.log(data?.data);
  return (
    <form onSubmit={handleSubmit(onSubmit)} noValidate>
      <Stack spacing={2}>
        <TextField
          label="Enter a show or movie"
          type="text"
          {...register("tvSearch")}
          error={!!errors.tvSearch}
          helperText={errors.tvSearch?.message}
        />
        <Button type="submit" variant="contained">
          Search
        </Button>
      </Stack>
    </form>
  );
}

export default ShowBox;

内容的提问来源于stack exchange,提问作者Brenden Baio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 07:17:04