mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-28 07:14:40 +08:00
refactor: replace useSWR with custom hooks for update and network interfaces (#6195)
This commit is contained in:
@@ -10,14 +10,13 @@ import { useLockFn } from "ahooks";
|
|||||||
import { useCallback, useEffect, useMemo, useReducer } from "react";
|
import { useCallback, useEffect, useMemo, useReducer } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import useSWR from "swr";
|
|
||||||
|
|
||||||
import { useServiceInstaller } from "@/hooks/use-service-installer";
|
import { useServiceInstaller } from "@/hooks/use-service-installer";
|
||||||
import { useSystemState } from "@/hooks/use-system-state";
|
import { useSystemState } from "@/hooks/use-system-state";
|
||||||
|
import { useUpdate } from "@/hooks/use-update";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { getSystemInfo } from "@/services/cmds";
|
import { getSystemInfo } from "@/services/cmds";
|
||||||
import { showNotice } from "@/services/notice-service";
|
import { showNotice } from "@/services/notice-service";
|
||||||
import { checkUpdateSafe as checkUpdate } from "@/services/update";
|
|
||||||
import { version as appVersion } from "@root/package.json";
|
import { version as appVersion } from "@root/package.json";
|
||||||
|
|
||||||
import { EnhancedCard } from "./enhanced-card";
|
import { EnhancedCard } from "./enhanced-card";
|
||||||
@@ -52,6 +51,18 @@ export const SystemInfoCard = () => {
|
|||||||
const { isAdminMode, isSidecarMode } = useSystemState();
|
const { isAdminMode, isSidecarMode } = useSystemState();
|
||||||
const { installServiceAndRestartCore } = useServiceInstaller();
|
const { installServiceAndRestartCore } = useServiceInstaller();
|
||||||
|
|
||||||
|
// 自动检查更新逻辑
|
||||||
|
const { checkUpdate: triggerCheckUpdate } = useUpdate(true, {
|
||||||
|
onSuccess: () => {
|
||||||
|
const now = Date.now();
|
||||||
|
localStorage.setItem("last_check_update", now.toString());
|
||||||
|
dispatchSystemState({
|
||||||
|
type: "set-last-check-update",
|
||||||
|
payload: new Date(now).toLocaleString(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// 系统信息状态
|
// 系统信息状态
|
||||||
const [systemState, dispatchSystemState] = useReducer(systemStateReducer, {
|
const [systemState, dispatchSystemState] = useReducer(systemStateReducer, {
|
||||||
osInfo: "",
|
osInfo: "",
|
||||||
@@ -109,7 +120,7 @@ export const SystemInfoCard = () => {
|
|||||||
|
|
||||||
timeoutId = window.setTimeout(() => {
|
timeoutId = window.setTimeout(() => {
|
||||||
if (verge?.auto_check_update) {
|
if (verge?.auto_check_update) {
|
||||||
checkUpdate().catch(console.error);
|
triggerCheckUpdate().catch(console.error);
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
@@ -118,26 +129,7 @@ export const SystemInfoCard = () => {
|
|||||||
window.clearTimeout(timeoutId);
|
window.clearTimeout(timeoutId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [verge?.auto_check_update, dispatchSystemState]);
|
}, [verge?.auto_check_update, dispatchSystemState, triggerCheckUpdate]);
|
||||||
|
|
||||||
// 自动检查更新逻辑
|
|
||||||
useSWR(
|
|
||||||
verge?.auto_check_update ? "checkUpdate" : null,
|
|
||||||
async () => {
|
|
||||||
const now = Date.now();
|
|
||||||
localStorage.setItem("last_check_update", now.toString());
|
|
||||||
dispatchSystemState({
|
|
||||||
type: "set-last-check-update",
|
|
||||||
payload: new Date(now).toLocaleString(),
|
|
||||||
});
|
|
||||||
return await checkUpdate();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
revalidateOnFocus: false,
|
|
||||||
refreshInterval: 24 * 60 * 60 * 1000, // 每天检查一次
|
|
||||||
dedupingInterval: 60 * 60 * 1000, // 1小时内不重复检查
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// 导航到设置页面
|
// 导航到设置页面
|
||||||
const goToSettings = useCallback(() => {
|
const goToSettings = useCallback(() => {
|
||||||
@@ -164,7 +156,7 @@ export const SystemInfoCard = () => {
|
|||||||
// 检查更新
|
// 检查更新
|
||||||
const onCheckUpdate = useLockFn(async () => {
|
const onCheckUpdate = useLockFn(async () => {
|
||||||
try {
|
try {
|
||||||
const info = await checkUpdate();
|
const info = await triggerCheckUpdate();
|
||||||
if (!info?.available) {
|
if (!info?.available) {
|
||||||
showNotice.success(
|
showNotice.success(
|
||||||
"settings.components.verge.advanced.notifications.latestVersion",
|
"settings.components.verge.advanced.notifications.latestVersion",
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import useSWR from "swr";
|
|
||||||
|
|
||||||
import { DialogRef } from "@/components/base";
|
import { DialogRef } from "@/components/base";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useUpdate } from "@/hooks/use-update";
|
||||||
import { checkUpdateSafe } from "@/services/update";
|
|
||||||
|
|
||||||
import { UpdateViewer } from "../setting/mods/update-viewer";
|
import { UpdateViewer } from "../setting/mods/update-viewer";
|
||||||
|
|
||||||
@@ -14,20 +12,9 @@ interface Props {
|
|||||||
|
|
||||||
export const UpdateButton = (props: Props) => {
|
export const UpdateButton = (props: Props) => {
|
||||||
const { className } = props;
|
const { className } = props;
|
||||||
const { verge } = useVerge();
|
|
||||||
const { auto_check_update } = verge || {};
|
|
||||||
|
|
||||||
const viewerRef = useRef<DialogRef>(null);
|
const viewerRef = useRef<DialogRef>(null);
|
||||||
|
|
||||||
const { data: updateInfo } = useSWR(
|
const { updateInfo } = useUpdate();
|
||||||
auto_check_update || auto_check_update === null ? "checkUpdate" : null,
|
|
||||||
checkUpdateSafe,
|
|
||||||
{
|
|
||||||
errorRetryCount: 2,
|
|
||||||
revalidateIfStale: false,
|
|
||||||
focusThrottleInterval: 36e5, // 1 hour
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!updateInfo?.available) return null;
|
if (!updateInfo?.available) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { useEffect, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import useSWR from "swr";
|
|
||||||
|
|
||||||
|
import { useRuntimeConfig } from "@/hooks/use-clash";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { useAppData } from "@/providers/app-data-context";
|
import { useAppData } from "@/providers/app-data-context";
|
||||||
import { getRuntimeConfig } from "@/services/cmds";
|
|
||||||
import delayManager from "@/services/delay";
|
import delayManager from "@/services/delay";
|
||||||
import { debugLog } from "@/utils/debug";
|
import { debugLog } from "@/utils/debug";
|
||||||
|
|
||||||
@@ -107,14 +106,7 @@ export const useRenderList = (
|
|||||||
const latencyTimeout = verge?.default_latency_timeout;
|
const latencyTimeout = verge?.default_latency_timeout;
|
||||||
|
|
||||||
// 获取运行时配置用于链式代理模式
|
// 获取运行时配置用于链式代理模式
|
||||||
const { data: runtimeConfig } = useSWR(
|
const { data: runtimeConfig } = useRuntimeConfig(!!isChainMode);
|
||||||
isChainMode ? "getRuntimeConfig" : null,
|
|
||||||
getRuntimeConfig,
|
|
||||||
{
|
|
||||||
revalidateOnFocus: false,
|
|
||||||
revalidateIfStale: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// 计算列数
|
// 计算列数
|
||||||
const col = useMemo(
|
const col = useMemo(
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ import { writeText } from "@tauri-apps/plugin-clipboard-manager";
|
|||||||
import type { Ref } from "react";
|
import type { Ref } from "react";
|
||||||
import { useImperativeHandle, useState } from "react";
|
import { useImperativeHandle, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import useSWR from "swr";
|
|
||||||
|
|
||||||
import { BaseDialog, DialogRef } from "@/components/base";
|
import { BaseDialog, DialogRef } from "@/components/base";
|
||||||
import { getNetworkInterfacesInfo } from "@/services/cmds";
|
import { useNetworkInterfaces } from "@/hooks/use-network";
|
||||||
import { showNotice } from "@/services/notice-service";
|
import { showNotice } from "@/services/notice-service";
|
||||||
|
|
||||||
export function NetworkInterfaceViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
export function NetworkInterfaceViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||||
@@ -22,13 +21,7 @@ export function NetworkInterfaceViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
|||||||
close: () => setOpen(false),
|
close: () => setOpen(false),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { data: networkInterfaces } = useSWR(
|
const { networkInterfaces } = useNetworkInterfaces();
|
||||||
"clash-verge-rev-internal://network-interfaces",
|
|
||||||
getNetworkInterfacesInfo,
|
|
||||||
{
|
|
||||||
fallbackData: [], // default data before fetch
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
|
|||||||
@@ -8,13 +8,12 @@ import { useImperativeHandle, useMemo, useRef, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import rehypeRaw from "rehype-raw";
|
import rehypeRaw from "rehype-raw";
|
||||||
import useSWR from "swr";
|
|
||||||
|
|
||||||
import { BaseDialog, DialogRef } from "@/components/base";
|
import { BaseDialog, DialogRef } from "@/components/base";
|
||||||
|
import { useUpdate } from "@/hooks/use-update";
|
||||||
import { portableFlag } from "@/pages/_layout";
|
import { portableFlag } from "@/pages/_layout";
|
||||||
import { showNotice } from "@/services/notice-service";
|
import { showNotice } from "@/services/notice-service";
|
||||||
import { useSetUpdateState, useUpdateState } from "@/services/states";
|
import { useSetUpdateState, useUpdateState } from "@/services/states";
|
||||||
import { checkUpdateSafe as checkUpdate } from "@/services/update";
|
|
||||||
|
|
||||||
export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -23,11 +22,7 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
|||||||
const updateState = useUpdateState();
|
const updateState = useUpdateState();
|
||||||
const setUpdateState = useSetUpdateState();
|
const setUpdateState = useSetUpdateState();
|
||||||
|
|
||||||
const { data: updateInfo } = useSWR("checkUpdate", checkUpdate, {
|
const { updateInfo } = useUpdate();
|
||||||
errorRetryCount: 2,
|
|
||||||
revalidateIfStale: false,
|
|
||||||
focusThrottleInterval: 36e5, // 1 hour
|
|
||||||
});
|
|
||||||
|
|
||||||
const [downloaded, setDownloaded] = useState(0);
|
const [downloaded, setDownloaded] = useState(0);
|
||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
|
|||||||
@@ -51,11 +51,12 @@ const validatePorts = (patch: ClashInfoPatch) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useRuntimeConfig = (shouldFetch: boolean = true) => {
|
||||||
|
return useSWR(shouldFetch ? "getRuntimeConfig" : null, getRuntimeConfig);
|
||||||
|
};
|
||||||
|
|
||||||
export const useClash = () => {
|
export const useClash = () => {
|
||||||
const { data: clash, mutate: mutateClash } = useSWR(
|
const { data: clash, mutate: mutateClash } = useRuntimeConfig();
|
||||||
"getRuntimeConfig",
|
|
||||||
getRuntimeConfig,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data: versionData, mutate: mutateVersion } = useSWR(
|
const { data: versionData, mutate: mutateVersion } = useSWR(
|
||||||
"getVersion",
|
"getVersion",
|
||||||
|
|||||||
22
src/hooks/use-network.ts
Normal file
22
src/hooks/use-network.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
import { getNetworkInterfacesInfo } from "@/services/cmds";
|
||||||
|
|
||||||
|
export const useNetworkInterfaces = () => {
|
||||||
|
const { data, error, isLoading, mutate } = useSWR(
|
||||||
|
"getNetworkInterfacesInfo",
|
||||||
|
getNetworkInterfacesInfo,
|
||||||
|
{
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
revalidateOnReconnect: false,
|
||||||
|
fallbackData: [],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
networkInterfaces: data || [],
|
||||||
|
loading: isLoading,
|
||||||
|
error,
|
||||||
|
mutate,
|
||||||
|
};
|
||||||
|
};
|
||||||
46
src/hooks/use-update.ts
Normal file
46
src/hooks/use-update.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import useSWR, { SWRConfiguration } from "swr";
|
||||||
|
|
||||||
|
import { checkUpdateSafe } from "@/services/update";
|
||||||
|
|
||||||
|
import { useVerge } from "./use-verge";
|
||||||
|
|
||||||
|
export interface UpdateInfo {
|
||||||
|
version: string;
|
||||||
|
body: string;
|
||||||
|
date: string;
|
||||||
|
available: boolean;
|
||||||
|
downloadAndInstall: (onEvent?: any) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useUpdate = (
|
||||||
|
enabled: boolean = true,
|
||||||
|
options?: SWRConfiguration,
|
||||||
|
) => {
|
||||||
|
const { verge } = useVerge();
|
||||||
|
const { auto_check_update } = verge || {};
|
||||||
|
|
||||||
|
// Determine if we should check for updates
|
||||||
|
// If enabled is explicitly false, don't check
|
||||||
|
// Otherwise, respect the auto_check_update setting (or default to true if null/undefined for manual triggers)
|
||||||
|
const shouldCheck = enabled && auto_check_update !== false;
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: updateInfo,
|
||||||
|
mutate: checkUpdate,
|
||||||
|
isValidating,
|
||||||
|
} = useSWR(shouldCheck ? "checkUpdate" : null, checkUpdateSafe, {
|
||||||
|
errorRetryCount: 2,
|
||||||
|
revalidateIfStale: false,
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
focusThrottleInterval: 36e5, // 1 hour
|
||||||
|
refreshInterval: 24 * 60 * 60 * 1000, // 24 hours
|
||||||
|
dedupingInterval: 60 * 60 * 1000, // 1 hour
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
updateInfo,
|
||||||
|
checkUpdate,
|
||||||
|
loading: isValidating,
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user