React Query中QueryErrorResetBoundary重试按钮失效问题排查
问题分析与解决思路
首先明确核心问题:当API返回500错误时,React Query重试4次后抛出错误被错误边界捕获,但点击重试按钮无响应,查询处于inactive状态。这主要是组件卸载导致查询失活,以及重置错误后未触发查询重新执行两个原因导致。
1. 移除组件卸载逻辑,避免查询进入inactive状态
你的DeckListContainer中存在if (!data) return null的判断,当查询失败时,data为undefined会直接返回null,导致组件卸载,React Query会将该查询标记为inactive状态。后续即使重置错误边界,inactive的查询也不会自动重新发起请求。
修改DeckListContainer代码:
export default function DeckListContainer() { const {data, fetchNextPage} = useGetDeckInfiniteQuery() // 移除返回null的逻辑,用可选链处理空值 const paginatedData: DeckType[] = data?.pages.map(page => page.data).flat() ?? [] return ( <BaseFlatList data={paginatedData} keyExtractor={item => item.id} renderItem={({item}) => <DeckListItem item={item}/>} onEndReached={() => fetchNextPage()} onEndReachedThreshold={0.8} /> ); }
2. 重置错误边界时手动触发查询重新执行
QueryErrorResetBoundary的reset函数仅清除React Query的错误状态,但对于inactive的查询,需要手动触发重新请求。修改ScreenViewQueryBoundaries组件,在重置时调用refetchQueries:
import { useQueryClient } from '@tanstack/react-query'; export const ScreenViewQueryBoundaries = ({children, loading}: Props) => { const queryClient = useQueryClient(); return ( <QueryErrorResetBoundary> {({reset}) => ( <ErrorBoundary onReset={() => { reset(); // 替换为你的useGetDeckInfiniteQuery对应的queryKey queryClient.refetchQueries({ queryKey: ['deck'] }); }} FallbackComponent={(props) => { return ( <ScreenView> <Button mode="outlined" onPress={() => props.resetErrorBoundary()}>Retry</Button> </ScreenView> ) }}> <Suspense fallback={loading ?? <QueryLoadingView/>}> {children} </Suspense> </ErrorBoundary> )} </QueryErrorResetBoundary> ); };
3. 确保queryFn正确抛出错误
检查useGetDeckInfiniteQuery的queryFn,必须确保API返回错误时主动抛出异常,否则React Query无法感知查询失败:
export const useGetDeckInfiniteQuery = () => { return useInfiniteQuery({ queryKey: ['deck'], queryFn: async ({ pageParam = 1 }) => { const response = await fetch(`/api/decks?page=${pageParam}`); // 非2xx状态码时抛出错误 if (!response.ok) { throw new Error('Failed to fetch deck data'); } return response.json(); }, getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined, getPreviousPageParam: (firstPage) => firstPage.prevPage ?? undefined, }); };
4. 可选:调整查询配置,优化重试触发逻辑
如果希望组件重新挂载时自动重新请求,可在查询配置中添加refetchOnMount: 'always':
方式1:在单个查询中配置
export const useGetDeckInfiniteQuery = () => { return useInfiniteQuery({ // ...其他配置 refetchOnMount: 'always', }); };
方式2:全局QueryClient配置
const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: Infinity, refetchOnWindowFocus: false, suspense: true, refetchOnMount: 'always', // 全局生效 } } })
内容的提问来源于stack exchange,提问作者tamke001
相关产品推荐
相关产品推荐

