使用TanStack Query时UI未随ID变更重新渲染的问题排查
问题:TanStack Query ID变更时UI不更新,仅切换标签页后生效
我用TanStack Query封装了自定义Hook获取API数据,ID参数传递正常,但ID变更时UI不会自动更新,只有切换标签页返回后才会更新。但用普通Axios请求的代码可以正常更新UI,求解决。
自定义Hook代码:
import { useQuery } from "@tanstack/react-query"; import { ApiInstance } from "../axios/axios"; import { Endpoints } from "../endpoints/endpoints"; export const useGetApiDetails = (id) => { const { data, isLoading } = useQuery(["getApiDetails"], { queryFn: async () => { const { data } = await ApiInstance.get(Endpoints.getApiDetails(id)); return data; }, }); return { data, isLoading }; };
Home组件使用代码:
const Home = () => { const { pathname } = useLocation(); const id = pathname.replace("/", ""); const { data, isLoading } = useGetApiDetails(id); const [apiDetails, setApiDetails] = useState(); const [requestParamList, setRequestParamList] = useState(); useEffect(() => { setApiDetails(data?.data?.apiDetails); setRequestParamList(data?.data?.requestParamList); }, [data]); return ( <div className="w-full h-full flex"> {/* {isLoading ? ( <h1>Loading...</h1> ) : ( */} <> <LeftSide apiDetails={apiDetails} requiredParams={requestParamList} /> <RightSide apiDetails={apiDetails} requiredParams={requestParamList} /> </> {/* )} */} </div> ); }; export default Home;
正常工作的普通Axios代码:
const { pathname } = useLocation(); const id = pathname.replace("/", ""); const [apiDetails, setApiDetails] = useState(); const [requestParamList, setRequestParamList] = useState(); const fetchData = async (id) => { const response = await ApiInstance.get(Endpoints.getApiDetails(id)) console.log(response.data, "res"); setApiDetails(response.data.data.apiDetails) setRequestParamList(response.data.data.requestParamList) } useEffect(() => { fetchData(id) }, [id]);
解决方案
1. 修复自定义Hook的查询键
TanStack Query 通过**查询键(Query Key)**识别不同请求、管理缓存并决定是否重新发起请求。你的代码里查询键是固定的["getApiDetails"],未包含id参数,导致id变化时,TanStack Query认为是同一个请求,不会重新调用queryFn。
修改自定义Hook,把id加入查询键:
export const useGetApiDetails = (id) => { const { data, isLoading } = useQuery( ["getApiDetails", id], // 将id加入查询键,让键随id动态变化 { queryFn: async () => { const { data } = await ApiInstance.get(Endpoints.getApiDetails(id)); return data; }, } ); return { data, isLoading }; };
2. 移除冗余的状态和副作用
Home组件里用useState和useEffect同步TanStack Query返回的data完全没必要,直接使用data即可减少冗余代码,同时避免状态不同步问题:
const Home = () => { const { pathname } = useLocation(); const id = pathname.replace("/", ""); const { data, isLoading } = useGetApiDetails(id); // 直接从data解构需要的字段 const apiDetails = data?.data?.apiDetails; const requestParamList = data?.data?.requestParamList; return ( <div className="w-full h-full flex"> {isLoading ? ( <h1>Loading...</h1> ) : ( <> <LeftSide apiDetails={apiDetails} requiredParams={requestParamList} /> <RightSide apiDetails={apiDetails} requiredParams={requestParamList} /> </> )} </div> ); }; export default Home;
原因说明
- 普通Axios代码中,
useEffect监听id变化,每次id改变都会重新调用fetchData,因此UI能正常更新。 - TanStack Query默认缓存请求结果,只有当查询键变化时才会重新发起请求。之前的查询键不包含
id,所以id变化不会触发新请求;切换标签页时,TanStack Query会触发后台重新获取数据,这才让UI更新。
内容的提问来源于stack exchange,提问作者Santhosh
相关产品推荐
相关产品推荐

