React中TanStack Query点击按钮首次加载旧数据问题求助
问题分析与解决方案
核心问题
- Query Key未关联分类参数:你的
queryKey仅设置为["topContest"],未包含category变量。React Query依赖queryKey识别查询唯一性,分类切换时queryKey不变,会直接返回旧缓存数据,而非发起新请求。 - Enabled配置错误:
enabled: !category意味着仅当category为空时才触发查询,但初始category是'Gaming Contest',导致首次渲染不会自动执行查询,必须手动调用refetch,这是切换时需要两次点击的关键原因之一。 - 冗余状态维护:手动维护
loading和cardData状态完全多余,useQuery本身已提供isLoading和data字段,额外维护反而容易造成状态不同步。
修正后的代码
import React, { useState } from "react"; import AnimatedNumbers from "../../component/AnimatedNumbers"; import InViewParagraph from "../../component/InViewParagraph"; import useAxiosPublic from "../../hooks/useAxiosPublic"; import { useQuery } from "@tanstack/react-query"; import ContestCard from "../../component/ContestCard"; import { Link } from "react-router-dom"; const ContestType = () => { const axiosPublic = useAxiosPublic(); const [category, setCategory] = useState('Gaming Contest'); const { isLoading, error, data: cardData = [], } = useQuery({ // queryKey包含category,确保分类切换时触发新查询 queryKey: ["topContest", category], // 默认enabled为true,自动触发初始查询与分类切换后的新查询 queryFn: async () => { const res = await axiosPublic.get(`/contest?contest_category=${category}&size=4`); return res.data; }, }); const CustomLink = ({ href, title, className = "" }) => { return ( <button onClick={() => handleCategoryChange(title)} className={`${className} relative group`} > {title} <span className={`h-0.5 w-0 group-hover:w-full transition-[width] ease duration-300 inline-block bg-red-600 absolute left-0 -bottom-0.5 `} > </span> </button> ); }; const handleCategoryChange = (title) => { // 仅更新category,React Query会自动根据新queryKey重新查询 setCategory(title); }; return ( <div id="contesttype" className="bg-[#EEF1F4]"> <div className="grid place-items-center pt-20 capitalize"> <span className="inline-block text-7xl font-bold text-yellow-400"> <AnimatedNumbers value={100} />+{" "} <span className="font-normal text-slate-950">Contest to Join</span> </span> <InViewParagraph className="py-10 text-lg max-w-2xl text-center" text="100+ Contest present for you to choose. Join today, Participate in a contest. And unleash your inner potential." /> <div className="flex items-center justify-center gap-5"> <ul className="flex items-center justify-center gap-5 pb-10"> <li> <CustomLink title="Medical Contest" /> </li> <li> <CustomLink title="Gaming Contest" /> </li> {/* 可添加其他分类按钮 */} </ul> </div> <div> {isLoading ? ( <p>Loading...</p> ) : ( <div className="grid gap-5 lg:grid-cols-4 md:grid-cols-2 grid-cols-1"> {cardData.map((contest) => ( <ContestCard key={contest._id} contest={contest} /> ))} </div> )} </div> </div> </div> ); }; export default ContestType;
关键修改说明
- Query Key更新:将
queryKey改为["topContest", category],确保分类变化时React Query识别为新查询,自动发起请求并更新数据。 - 移除冗余配置:删掉
enabled: !category,useQuery默认会自动触发初始查询与参数变化后的新查询,无需手动调用refetch。 - 简化状态管理:移除手动维护的
loading和cardData,直接使用useQuery返回的isLoading和data,避免状态不同步问题。 - 精简事件处理:
handleCategoryChange仅需更新category,加载状态和数据更新完全由React Query自动处理。
内容的提问来源于stack exchange,提问作者Moshiur Rahman
相关产品推荐
相关产品推荐

