为何该HOC会导致RTK Query陷入无限请求循环?
问题原因
你的withLoading高阶组件在isLoading为true时,会直接渲染Loading...而不渲染被包裹的Nav组件,这会导致Nav被卸载。而Nav内部的useAuthenticateQuery会在组件挂载时自动发起请求,卸载时取消请求。
当服务器宕机请求失败时,RTK Query默认会触发重试机制,进而形成无限循环:
Home中isLoading变为true,HOC渲染Loading,Nav卸载,请求被取消;- RTK Query检测到请求失败(被取消也算失败场景),发起重试,
isLoading再次变为true; - 重试请求再次失败,
isLoading变为false,HOC渲染Nav,Nav挂载后再次触发useAuthenticateQuery发起请求; - 重复上述流程,陷入无限循环。
解决方案
有两种可行的修复方式,可根据需求选择:
方式一:始终渲染Nav组件,避免卸载
修改Loading.tsx中的高阶组件,确保不管isLoading状态如何,被包裹的组件始终存在(可通过样式叠加Loading层),这样组件不会被卸载,也就不会重复触发请求:
import React, { FC } from "react"; interface props { isLoading: boolean; } export function withLoading<T extends props = props>(WrappedComponent: FC<T>) { const ComponentWithLoading = (props: T) => ( <div style={{ position: 'relative' }}> {/* 叠加Loading层,isLoading时显示 */} {props.isLoading && ( <div style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, background: 'rgba(255,255,255,0.8)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}> Loading... </div> )} {/* 始终渲染原组件 */} <WrappedComponent {...props} /> </div> ); // 添加调试用的组件名称 ComponentWithLoading.displayName = `WithLoading(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`; return ComponentWithLoading; }
方式二:将请求逻辑移到父组件,避免子组件触发请求
把useAuthenticateQuery从Nav移到Home组件,将数据通过props传给Nav,这样Nav只负责展示数据,不会触发请求:
修改Nav.tsx
import { FC } from "react"; import { withLoading } from "../../components/Loading"; // 定义Nav的props类型 interface NavProps { userData?: { displayName?: string; email?: string; }; isLoading: boolean; } const Nav: FC<NavProps> = ({ userData }) => { return ( <h1> {userData?.displayName} {userData?.email} </h1> ); } export default withLoading(Nav);
修改index.tsx
'use client' import Nav from "./login/Nav"; import { useAuthenticateQuery } from "@/store"; export default function Home() { const { data, error, isLoading, refetch } = useAuthenticateQuery(); return ( <Nav isLoading={isLoading} userData={data?.data} /> ) }
内容的提问来源于stack exchange,提问作者João Pedro
相关产品推荐
相关产品推荐

