React Query返回空对象:自定义Hook封装与调用的正确实现
正确封装支持日期参数的TanStack Query自定义Hook
问题根源分析
原实现存在三个核心问题:
- 自定义Hook未接收
date参数,导致date变量未定义,触发编译错误 - 额外维护
useState和useEffect属于冗余操作:TanStack Query的useQuery返回的data本身是响应式状态,无需手动同步到本地状态 - 调用时的
useEffect依赖为空数组,仅执行一次,后续Query数据更新无法同步到组件状态,导致games始终为空
规范实现方案
1. 修正后的自定义Hook
import { useQuery } from '@tanstack/react-query'; // 假设apiGetUpcomingGames是已实现的API请求函数 const apiGetUpcomingGames = async (date: string | Date): Promise<Game[]> => { const response = await fetch(`/api/upcoming-games?date=${date}`); if (!response.ok) throw new Error('请求失败'); return response.json(); }; const useGamesApi = (date: string | Date) => { const queryResult = useQuery({ queryKey: ['upcoming', date], // 将date作为queryKey一部分,自动触发参数变更后的重新请求 queryFn: () => apiGetUpcomingGames(date), // 移除冗余的onSuccess回调,直接依赖Query自身的响应式数据 }); // 按需包装返回值,简化组件调用 return { games: queryResult.data ?? [], isLoading: queryResult.isLoading, error: queryResult.error, refetch: queryResult.refetch, // 暴露手动刷新方法(可选) }; }; export default useGamesApi;
2. 组件调用示例
import { useState } from 'react'; import useGamesApi from './useGamesApi'; const GameList = () => { // 维护日期参数的本地状态,用于修改筛选条件 const [selectedDate, setSelectedDate] = useState<string>( new Date().toISOString().split('T')[0] ); // 直接传入日期参数,获取响应式状态 const { games, isLoading, error } = useGamesApi(selectedDate); if (isLoading) return <div>加载中...</div>; if (error) return <div>加载失败:{(error as Error).message}</div>; return ( <> <input type="date" value={selectedDate} onChange={(e) => setSelectedDate(e.target.value)} /> <ul> {games.map(game => ( <li key={game.id}>{game.title}</li> ))} </ul> </> ); }; export default GameList;
核心优化点
- 参数驱动请求:将
date作为Hook的入参和queryKey的一部分,参数变更时自动触发新请求 - 移除冗余状态:直接使用TanStack Query管理的响应式数据,避免
useState+useEffect的同步冗余 - 简化组件调用:Hook封装Query的加载、错误、数据状态,组件只需关注业务渲染逻辑
内容的提问来源于stack exchange,提问作者geo10
相关产品推荐
相关产品推荐

