如何用RTK Query轮询API直至获取'CLOSED'工作流状态?
如何用RTK Query实现工作流状态的轮询直到状态为'CLOSED'
方案1:利用RTK Query内置的refetchInterval实现条件轮询
RTK Query的useQuery钩子原生支持refetchInterval参数,可动态控制是否开启自动轮询,完全符合React钩子规则,无需手动编写定时器和useEffect:
const LoaderBox = (props: LoaderBoxProps) => { const { buildingId, devicesId } = props; const { data: runWorkflowData, error: runWorkflowError, isSuccess: isRunWorkflowSuccess, } = useRunWorfklowQuery({ buildingId, devicesId }); const { data: runStatusData, error: runStatusError, isLoading: runStatusLoading, } = useGetWorkflowStatusQuery( isRunWorkflowSuccess ? { buildingId, runId: runWorkflowData.runId } : skipToken, { // 仅当状态未变为CLOSED时,每5秒重新请求一次 refetchInterval: (data) => data?.runStatus !== 'CLOSED' ? 5000 : false, // 可选:切换到后台标签页时仍保持轮询 refetchIntervalInBackground: true, } ); // 直接通过接口返回值判断状态,无需额外维护useState const isRunFinished = runStatusData?.runStatus === 'CLOSED'; return ( <> {!runWorkflowError ? ( <> <Text>Requested workflow run</Text> {isRunFinished ? <Text>Workflow finished</Text> : <Text>Workflow in progress</Text>} </> ) : null} </> ); };
方案2:正确使用lazyQuery手动控制轮询
如果需要更精细的自定义逻辑,可使用lazyQuery,注意正确解构返回值:lazyQuery返回的数组第一个元素是触发请求的函数,第二个是查询状态:
const LoaderBox = (props: LoaderBoxProps) => { const { buildingId, devicesId } = props; const { data: runWorkflowData, error: runWorkflowError, isSuccess: isRunWorkflowSuccess, } = useRunWorfklowQuery({ buildingId, devicesId }); // 解构lazyQuery:第一个是触发函数,第二个是状态对象 const [triggerGetStatus, { data: runStatusData }] = api.useLazyGetWorkflowStatusQuery(); const [isRunFinished, setIsRunFinished] = useState(false); useEffect(() => { let intervalId: NodeJS.Timeout; // 工作流启动成功且未结束时,开始轮询 if (isRunWorkflowSuccess && runWorkflowData?.runId && !isRunFinished) { const fetchStatus = async () => { const result = await triggerGetStatus({ buildingId, runId: runWorkflowData.runId }); if (result.data?.runStatus === 'CLOSED') { setIsRunFinished(true); clearInterval(intervalId); } }; // 发起首次请求 fetchStatus(); // 设置循环定时器 intervalId = setInterval(fetchStatus, 5000); } // 组件卸载或依赖变更时清理定时器 return () => clearInterval(intervalId); }, [isRunWorkflowSuccess, runWorkflowData, triggerGetStatus, isRunFinished, buildingId]); return ( <> {!runWorkflowError ? ( <> <Text>Requested workflow run</Text> {isRunFinished ? <Text>Workflow finished</Text> : <Text>Workflow in progress</Text>} </> ) : null} </> ); };
关于自定义baseQuery的重试问题
你的自定义getBaseQuery并非基于RTK Query内置的fetchBaseQuery,因此不支持原生retry参数。若需要重试逻辑,可手动在getBaseQuery中实现:
const getBaseQuery = async (apiPromise: Promise<ServiceModel>, retryCount = 3) => { let attempt = 0; while (attempt < retryCount) { try { const response = await apiPromise; if (response) { return { data: response }; } throw new Error('No data received from service'); } catch (err) { attempt++; if (attempt === retryCount) { return { error: err }; } // 重试前等待1秒 await new Promise(resolve => setTimeout(resolve, 1000)); } } return { error: new Error('Max retries exceeded') }; };
不过对于轮询场景,方案1的refetchInterval已足够满足需求,无需额外添加重试逻辑。
内容的提问来源于stack exchange,提问作者Manthan Jamdagni
相关产品推荐
相关产品推荐

