mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-08 02:52:07 +08:00
refactor(app-data): split monolithic context into focused SWR hooks (#5576)
* refactor(app-data): split monolithic context into focused SWR hooks * refactor(swr): unify polling and consolidate proxy/config/provider data flow
This commit is contained in:
@@ -3,8 +3,14 @@ import { Divider, Stack, Typography } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import {
|
||||
useAppUptime,
|
||||
useClashConfig,
|
||||
useRulesData,
|
||||
useSystemProxyAddress,
|
||||
useSystemProxyData,
|
||||
} from "@/hooks/app-data";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
|
||||
import { EnhancedCard } from "./enhanced-card";
|
||||
|
||||
@@ -19,7 +25,14 @@ const formatUptime = (uptimeMs: number) => {
|
||||
export const ClashInfoCard = () => {
|
||||
const { t } = useTranslation();
|
||||
const { version: clashVersion } = useClash();
|
||||
const { clashConfig, rules, uptime, systemProxyAddress } = useAppData();
|
||||
const { clashConfig } = useClashConfig();
|
||||
const { sysproxy } = useSystemProxyData();
|
||||
const { rules } = useRulesData();
|
||||
const { uptime } = useAppUptime();
|
||||
const systemProxyAddress = useSystemProxyAddress({
|
||||
clashConfig,
|
||||
sysproxy,
|
||||
});
|
||||
|
||||
// 使用useMemo缓存格式化后的uptime,避免频繁计算
|
||||
const formattedUptime = useMemo(() => formatUptime(uptime), [uptime]);
|
||||
|
||||
@@ -9,8 +9,8 @@ import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { closeAllConnections } from "tauri-plugin-mihomo-api";
|
||||
|
||||
import { useClashConfig } from "@/hooks/app-data";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import { patchClashMode } from "@/services/cmds";
|
||||
import type { TranslationKey } from "@/types/generated/i18n-keys";
|
||||
|
||||
@@ -41,7 +41,7 @@ const MODE_META: Record<
|
||||
export const ClashModeCard = () => {
|
||||
const { t } = useTranslation();
|
||||
const { verge } = useVerge();
|
||||
const { clashConfig, refreshClashConfig } = useAppData();
|
||||
const { clashConfig, refreshClashConfig } = useClashConfig();
|
||||
|
||||
// 支持的模式列表
|
||||
const modeList = CLASH_MODES;
|
||||
|
||||
@@ -34,10 +34,10 @@ import { useNavigate } from "react-router";
|
||||
import { delayGroup, healthcheckProxyProvider } from "tauri-plugin-mihomo-api";
|
||||
|
||||
import { EnhancedCard } from "@/components/home/enhanced-card";
|
||||
import { useClashConfig, useProxiesData, useRulesData } from "@/hooks/app-data";
|
||||
import { useProfiles } from "@/hooks/use-profiles";
|
||||
import { useProxySelection } from "@/hooks/use-proxy-selection";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import delayManager from "@/services/delay";
|
||||
|
||||
// 本地存储的键名
|
||||
@@ -100,7 +100,9 @@ export const CurrentProxyCard = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
const { proxies, clashConfig, refreshProxy, rules } = useAppData();
|
||||
const { proxies, refreshProxy } = useProxiesData();
|
||||
const { clashConfig } = useClashConfig();
|
||||
const { rules } = useRulesData();
|
||||
const { verge } = useVerge();
|
||||
const { current: currentProfile } = useProfiles();
|
||||
const autoDelayEnabled = verge?.enable_auto_delay_detection ?? false;
|
||||
|
||||
@@ -24,7 +24,7 @@ import { useCallback, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router";
|
||||
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import { useRefreshAll } from "@/hooks/app-data";
|
||||
import { openWebUrl, updateProfile } from "@/services/cmds";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
@@ -281,7 +281,7 @@ export const HomeProfileCard = ({
|
||||
}: HomeProfileCardProps) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const { refreshAll } = useAppData();
|
||||
const refreshAll = useRefreshAll();
|
||||
|
||||
// 更新当前订阅
|
||||
const [updating, setUpdating] = useState(false);
|
||||
|
||||
@@ -22,7 +22,7 @@ import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { updateProxyProvider } from "tauri-plugin-mihomo-api";
|
||||
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import { useProxiesData, useProxyProvidersData } from "@/hooks/app-data";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
|
||||
@@ -48,7 +48,8 @@ const parseExpire = (expire?: number) => {
|
||||
export const ProviderButton = () => {
|
||||
const { t } = useTranslation();
|
||||
const [open, setOpen] = useState(false);
|
||||
const { proxyProviders, refreshProxy, refreshProxyProviders } = useAppData();
|
||||
const { proxyProviders, refreshProxyProviders } = useProxyProvidersData();
|
||||
const { refreshProxy } = useProxiesData();
|
||||
const [updating, setUpdating] = useState<Record<string, boolean>>({});
|
||||
|
||||
// 检查是否有提供者
|
||||
@@ -175,8 +176,8 @@ export const ProviderButton = () => {
|
||||
<List sx={{ py: 0, minHeight: 250 }}>
|
||||
{Object.entries(proxyProviders || {})
|
||||
.sort()
|
||||
.map(([key, item]) => {
|
||||
const provider = item;
|
||||
.map(([key, provider]) => {
|
||||
if (!provider) return null;
|
||||
const time = dayjs(provider.updatedAt);
|
||||
const isUpdating = updating[key];
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ import {
|
||||
selectNodeForGroup,
|
||||
} from "tauri-plugin-mihomo-api";
|
||||
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import { useProxiesData } from "@/hooks/app-data";
|
||||
import { calcuProxies, updateProxyChainConfigInRuntime } from "@/services/cmds";
|
||||
|
||||
interface ProxyChainItem {
|
||||
@@ -199,7 +199,7 @@ export const ProxyChain = ({
|
||||
}: ProxyChainProps) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { proxies } = useAppData();
|
||||
const { proxies } = useProxiesData();
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
const markUnsavedChanges = useCallback(() => {
|
||||
onMarkUnsavedChanges?.();
|
||||
|
||||
@@ -15,9 +15,9 @@ import { useTranslation } from "react-i18next";
|
||||
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso";
|
||||
import { delayGroup, healthcheckProxyProvider } from "tauri-plugin-mihomo-api";
|
||||
|
||||
import { useProxiesData } from "@/hooks/app-data";
|
||||
import { useProxySelection } from "@/hooks/use-proxy-selection";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import { updateProxyChainConfigInRuntime } from "@/services/cmds";
|
||||
import delayManager from "@/services/delay";
|
||||
|
||||
@@ -61,7 +61,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
}>({ open: false, message: "" });
|
||||
|
||||
const { verge } = useVerge();
|
||||
const { proxies: proxiesData } = useAppData();
|
||||
const { proxies: proxiesData } = useProxiesData();
|
||||
const groups = proxiesData?.groups;
|
||||
const availableGroups = useMemo(() => groups ?? [], [groups]);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
import { useProxiesData } from "@/hooks/app-data";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import { getRuntimeConfig } from "@/services/cmds";
|
||||
import delayManager from "@/services/delay";
|
||||
|
||||
@@ -33,24 +33,8 @@ interface IProxyItem {
|
||||
}
|
||||
|
||||
// 代理组类型
|
||||
type ProxyGroup = {
|
||||
name: string;
|
||||
type: string;
|
||||
udp: boolean;
|
||||
xudp: boolean;
|
||||
tfo: boolean;
|
||||
mptcp: boolean;
|
||||
smux: boolean;
|
||||
history: {
|
||||
time: string;
|
||||
delay: number;
|
||||
}[];
|
||||
now: string;
|
||||
all: IProxyItem[];
|
||||
hidden?: boolean;
|
||||
icon?: string;
|
||||
testUrl?: string;
|
||||
provider?: string;
|
||||
type ProxyGroup = IProxyGroupItem & {
|
||||
now?: string;
|
||||
};
|
||||
|
||||
export interface IRenderItem {
|
||||
@@ -99,7 +83,7 @@ export const useRenderList = (
|
||||
selectedGroup?: string | null,
|
||||
) => {
|
||||
// 使用全局数据提供者
|
||||
const { proxies: proxiesData, refreshProxy } = useAppData();
|
||||
const { proxies: proxiesData, refreshProxy } = useProxiesData();
|
||||
const { verge } = useVerge();
|
||||
const { width } = useWindowWidth();
|
||||
const [headStates, setHeadState] = useHeadStateNew();
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { updateRuleProvider } from "tauri-plugin-mihomo-api";
|
||||
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import type { useRuleProvidersData, useRulesData } from "@/hooks/app-data";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
|
||||
// 辅助组件 - 类型框
|
||||
@@ -37,10 +37,22 @@ const TypeBox = styled(Box)<{ component?: React.ElementType }>(({ theme }) => ({
|
||||
lineHeight: 1.25,
|
||||
}));
|
||||
|
||||
export const ProviderButton = () => {
|
||||
type RuleProvidersHook = ReturnType<typeof useRuleProvidersData>;
|
||||
type RulesHook = ReturnType<typeof useRulesData>;
|
||||
|
||||
interface ProviderButtonProps {
|
||||
ruleProviders: RuleProvidersHook["ruleProviders"];
|
||||
refreshRuleProviders: RuleProvidersHook["refreshRuleProviders"];
|
||||
refreshRules: RulesHook["refreshRules"];
|
||||
}
|
||||
|
||||
export const ProviderButton = ({
|
||||
ruleProviders,
|
||||
refreshRuleProviders,
|
||||
refreshRules,
|
||||
}: ProviderButtonProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [open, setOpen] = useState(false);
|
||||
const { ruleProviders, refreshRules, refreshRuleProviders } = useAppData();
|
||||
const [updating, setUpdating] = useState<Record<string, boolean>>({});
|
||||
|
||||
// 检查是否有提供者
|
||||
@@ -163,8 +175,8 @@ export const ProviderButton = () => {
|
||||
<List sx={{ py: 0, minHeight: 250 }}>
|
||||
{Object.entries(ruleProviders || {})
|
||||
.sort()
|
||||
.map(([key, item]) => {
|
||||
const provider = item;
|
||||
.map(([key, provider]) => {
|
||||
if (!provider) return null;
|
||||
const time = dayjs(provider.updatedAt);
|
||||
const isUpdating = updating[key];
|
||||
|
||||
|
||||
@@ -20,15 +20,18 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useSWR, { mutate } from "swr";
|
||||
import { getBaseConfig } from "tauri-plugin-mihomo-api";
|
||||
import { mutate } from "swr";
|
||||
|
||||
import { BaseDialog, DialogRef, Switch } from "@/components/base";
|
||||
import { BaseFieldset } from "@/components/base/base-fieldset";
|
||||
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
||||
import { EditorViewer } from "@/components/profile/editor-viewer";
|
||||
import {
|
||||
useClashConfig,
|
||||
useSystemProxyAddress,
|
||||
useSystemProxyData,
|
||||
} from "@/hooks/app-data";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { useAppData } from "@/providers/app-data-context";
|
||||
import {
|
||||
getAutotemProxy,
|
||||
getNetworkInterfacesInfo,
|
||||
@@ -92,9 +95,6 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||
const [hostOptions, setHostOptions] = useState<string[]>([]);
|
||||
|
||||
type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>;
|
||||
const [sysproxy, setSysproxy] = useState<SysProxy>();
|
||||
|
||||
type AutoProxy = Awaited<ReturnType<typeof getAutotemProxy>>;
|
||||
const [autoproxy, setAutoproxy] = useState<AutoProxy>();
|
||||
|
||||
@@ -129,12 +129,8 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
return "127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,localhost,*.local,*.crashlytics.com,<local>";
|
||||
};
|
||||
|
||||
const { data: clashConfig } = useSWR("getClashConfig", getBaseConfig, {
|
||||
revalidateOnFocus: false,
|
||||
revalidateIfStale: true,
|
||||
dedupingInterval: 1000,
|
||||
errorRetryInterval: 5000,
|
||||
});
|
||||
const { clashConfig } = useClashConfig();
|
||||
const { sysproxy, refreshSysproxy } = useSystemProxyData();
|
||||
|
||||
const prevMixedPortRef = useRef(clashConfig?.mixedPort);
|
||||
|
||||
@@ -168,7 +164,10 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
updateProxy();
|
||||
}, [clashConfig?.mixedPort, value.pac]);
|
||||
|
||||
const { systemProxyAddress } = useAppData();
|
||||
const systemProxyAddress = useSystemProxyAddress({
|
||||
clashConfig,
|
||||
sysproxy,
|
||||
});
|
||||
|
||||
// 为当前状态计算系统代理地址
|
||||
const getSystemProxyAddress = useMemo(() => {
|
||||
@@ -209,7 +208,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
pac_content: pac_file_content ?? DEFAULT_PAC,
|
||||
proxy_host: proxy_host ?? "127.0.0.1",
|
||||
});
|
||||
getSystemProxy().then((p) => setSysproxy(p));
|
||||
void refreshSysproxy();
|
||||
getAutotemProxy().then((p) => setAutoproxy(p));
|
||||
fetchNetworkInterfaces();
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user