You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 06:00:13