React Query中invalidateQueries引发Panel组件getApiData重复执行问题
问题:Panel组件中getApiData执行两次的解决方法
代码示例
function Dashboard(): ReactElement { const queryClient = useQueryClient(); const getDashboard = async () => { // 获取dashboard数据的逻辑 }; const { data, isLoading } = useQuery(['dashboard'], getDashboard); const onClick = () => { // 更新数据库中dashboard数据的逻辑 queryClient.invalidateQueries(['dashboard']); } if (isLoading) { return <div>Loading</div>; } return ( <div> <button onClick={onClick}>更新dashboard</button> {data?.map((card) => <Panel {...card} />)} </div> ); } function Panel(props: IPanel): ReactElement { const getApiData = async (props.id) => { // 获取用户选中的api数据逻辑 }; const { data, isLoading } = useQuery(['dashboard'], getApiData); if (isLoading) { return <div>Loading</div> } return ( <div> <InnerComponent {...data} /> </div> ); }
问题描述
我编写了上述代码,期望点击按钮时更新dashboard数据,通过queryClient.invalidateQueries(['dashboard'])清除dashboard缓存并刷新。但dashboard数据更新后传递给Panel组件时,Panel中的getApiData函数会执行两次,调整stalTime和cacheTime也无法解决该问题。
问题根源
- 查询键重复:Panel组件的useQuery使用了和Dashboard完全相同的查询键
['dashboard'],当调用invalidateQueries(['dashboard'])时,所有绑定该键的查询(包括所有Panel实例)都会被触发重新请求。 - 组件渲染触发查询:Dashboard数据更新后,Panel组件因props变化重新渲染,又会触发一次useQuery的执行,叠加后导致两次调用。
解决方法
1. 给Panel的查询键添加唯一标识
每个Panel对应不同的卡片数据,将props.id加入查询键,让每个Panel的查询独立:
// 修改Panel组件中的useQuery const { data, isLoading } = useQuery( ['dashboard', props.id], // 添加唯一id作为查询键后缀 () => getApiData(props.id) );
这样每个Panel的查询拥有独立缓存,不会互相干扰,也能精准控制单条数据的刷新。
2. 精准控制失效范围(可选)
如果只需要刷新Dashboard的主数据,不需要触发Panel的查询失效,可在invalidateQueries时添加exact: true参数,仅匹配完全一致的查询键:
// 修改Dashboard中的onClick逻辑 const onClick = () => { // 更新数据库中dashboard数据的逻辑 queryClient.invalidateQueries({ queryKey: ['dashboard'], exact: true // 仅匹配完全等于['dashboard']的查询 }); }
3. 优化组件渲染(可选)
给Panel组件添加React.memo包裹,避免props未变化时的不必要渲染,进一步减少查询触发的可能:
const Panel = React.memo((props: IPanel): ReactElement => { // 原Panel组件逻辑 });
内容的提问来源于stack exchange,提问作者raccoon_ko
相关产品推荐
相关产品推荐

