fix: eliminate error flash on startup by distinguishing loading from error state

- Change TQ_MIHOMO retryDelay from fixed 2000ms to exponential backoff
  (200ms → 400ms → 800ms, cap 3s) so core-dependent queries retry faster
- Expose isCoreDataPending from AppDataProvider to distinguish between
  data still loading vs actual errors
- ClashModeCard: show placeholder instead of "communication error" while
  core data is pending
- CurrentProxyCard: show empty space instead of "no active node" while
  core data is pending
This commit is contained in:
Tunglies 2026-04-06 02:14:33 +08:00
parent ec82b69786
commit 437fef1c30
No known key found for this signature in database
GPG Key ID: B9B01B389469B3E8
4 changed files with 27 additions and 7 deletions

View File

@ -41,7 +41,7 @@ const MODE_META: Record<
export const ClashModeCard = () => { export const ClashModeCard = () => {
const { t } = useTranslation() const { t } = useTranslation()
const { verge } = useVerge() const { verge } = useVerge()
const { clashConfig, refreshClashConfig } = useAppData() const { clashConfig, isCoreDataPending, refreshClashConfig } = useAppData()
// 支持的模式列表 // 支持的模式列表
const modeList = CLASH_MODES const modeList = CLASH_MODES
@ -57,8 +57,11 @@ export const ClashModeCard = () => {
if (currentModeKey) { if (currentModeKey) {
return t(MODE_META[currentModeKey].description) return t(MODE_META[currentModeKey].description)
} }
if (isCoreDataPending) {
return '\u00A0'
}
return t('home.components.clashMode.errors.communication') return t('home.components.clashMode.errors.communication')
}, [currentModeKey, t]) }, [currentModeKey, isCoreDataPending, t])
// 模式图标映射 // 模式图标映射
const modeIcons = useMemo( const modeIcons = useMemo(

View File

@ -105,7 +105,8 @@ export const CurrentProxyCard = () => {
const { t } = useTranslation() const { t } = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
const theme = useTheme() const theme = useTheme()
const { proxies, clashConfig, refreshProxy, rules } = useAppData() const { proxies, clashConfig, isCoreDataPending, refreshProxy, rules } =
useAppData()
const { verge } = useVerge() const { verge } = useVerge()
const { current: currentProfile } = useProfiles() const { current: currentProfile } = useProfiles()
const autoDelayEnabled = verge?.enable_auto_delay_detection ?? false const autoDelayEnabled = verge?.enable_auto_delay_detection ?? false
@ -911,7 +912,9 @@ export const CurrentProxyCard = () => {
</Box> </Box>
} }
> >
{currentProxy ? ( {isCoreDataPending ? (
<Box sx={{ py: 4 }} />
) : currentProxy ? (
<Box> <Box>
{/* 代理节点信息显示 */} {/* 代理节点信息显示 */}
<Box <Box

View File

@ -16,6 +16,7 @@ export interface AppDataContextType {
proxyProviders: Record<string, ProxyProvider> proxyProviders: Record<string, ProxyProvider>
ruleProviders: Record<string, RuleProvider> ruleProviders: Record<string, RuleProvider>
systemProxyAddress: string systemProxyAddress: string
isCoreDataPending: boolean
refreshProxy: () => Promise<any> refreshProxy: () => Promise<any>
refreshClashConfig: () => Promise<any> refreshClashConfig: () => Promise<any>

View File

@ -23,7 +23,7 @@ const TQ_MIHOMO = {
refetchOnReconnect: false, refetchOnReconnect: false,
staleTime: 1500, staleTime: 1500,
retry: 3, retry: 3,
retryDelay: 2000, retryDelay: (attempt: number) => Math.min(200 * 2 ** attempt, 3000),
} as const } as const
const TQ_DEFAULTS = { const TQ_DEFAULTS = {
@ -41,13 +41,21 @@ export const AppDataProvider = ({
}) => { }) => {
const { verge } = useVerge() const { verge } = useVerge()
const { data: proxiesData, refetch: refreshProxy } = useQuery({ const {
data: proxiesData,
isPending: isProxiesPending,
refetch: refreshProxy,
} = useQuery({
queryKey: ['getProxies'], queryKey: ['getProxies'],
queryFn: calcuProxies, queryFn: calcuProxies,
...TQ_MIHOMO, ...TQ_MIHOMO,
}) })
const { data: clashConfig, refetch: refreshClashConfig } = useQuery({ const {
data: clashConfig,
isPending: isClashConfigPending,
refetch: refreshClashConfig,
} = useQuery({
queryKey: ['getClashConfig'], queryKey: ['getClashConfig'],
queryFn: getBaseConfig, queryFn: getBaseConfig,
...TQ_MIHOMO, ...TQ_MIHOMO,
@ -323,6 +331,9 @@ export const AppDataProvider = ({
systemProxyAddress: calculateSystemProxyAddress(), systemProxyAddress: calculateSystemProxyAddress(),
// core 数据加载状态
isCoreDataPending: isProxiesPending || isClashConfigPending,
// 刷新方法 // 刷新方法
refreshProxy, refreshProxy,
refreshClashConfig, refreshClashConfig,
@ -335,6 +346,8 @@ export const AppDataProvider = ({
}, [ }, [
proxiesData, proxiesData,
clashConfig, clashConfig,
isProxiesPending,
isClashConfigPending,
rulesData, rulesData,
sysproxy, sysproxy,
runningMode, runningMode,