refactor(icon): extract icon cache logic into reusable hook

This commit is contained in:
Slinetrac 2026-01-01 16:35:36 +08:00
parent f3b9eedcf7
commit 522eccdd0e
No known key found for this signature in database
4 changed files with 69 additions and 81 deletions

View File

@ -9,10 +9,8 @@ import {
alpha,
styled,
} from "@mui/material";
import { convertFileSrc } from "@tauri-apps/api/core";
import { useEffect, useState } from "react";
import { downloadIconCache } from "@/services/cmds";
import { useIconCache } from "@/hooks/use-icon-cache";
interface Props {
type: "prepend" | "original" | "delete" | "append";
group: IProxyGroupConfig;
@ -38,40 +36,10 @@ export const GroupItem = (props: Props) => {
const dragListeners = sortable ? sortableListeners : undefined;
const dragNodeRef = sortable ? sortableSetNodeRef : undefined;
const [iconCachePath, setIconCachePath] = useState("");
useEffect(() => {
let cancelled = false;
const initIconCachePath = async () => {
const icon = group.icon?.trim() ?? "";
if (icon.startsWith("http")) {
try {
const fileName =
group.name.replaceAll(" ", "") + "-" + getFileName(icon);
const iconPath = await downloadIconCache(icon, fileName);
if (!cancelled) {
setIconCachePath(convertFileSrc(iconPath));
}
} catch {
if (!cancelled) {
setIconCachePath("");
}
}
} else if (!cancelled) {
setIconCachePath("");
}
};
void initIconCachePath();
return () => {
cancelled = true;
};
}, [group.icon, group.name]);
function getFileName(url: string) {
return url.substring(url.lastIndexOf("/") + 1);
}
const iconCachePath = useIconCache({
icon: group.icon,
cacheKey: group.name.replaceAll(" ", ""),
});
return (
<ListItem

View File

@ -13,12 +13,11 @@ import {
Chip,
Tooltip,
} from "@mui/material";
import { convertFileSrc } from "@tauri-apps/api/core";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useIconCache } from "@/hooks/use-icon-cache";
import { useVerge } from "@/hooks/use-verge";
import { downloadIconCache } from "@/services/cmds";
import { useThemeMode } from "@/services/states";
import { ProxyHead } from "./proxy-head";
@ -57,26 +56,11 @@ export const ProxyRender = (props: RenderProps) => {
const mode = useThemeMode();
const isDark = mode === "light" ? false : true;
const itembackgroundcolor = isDark ? "#282A36" : "#ffffff";
const [iconCachePath, setIconCachePath] = useState("");
const initIconCachePath = useCallback(async () => {
if (group.icon && group.icon.trim().startsWith("http")) {
const fileName =
group.name.replaceAll(" ", "") + "-" + getFileName(group.icon);
const iconPath = await downloadIconCache(group.icon, fileName);
setIconCachePath(convertFileSrc(iconPath));
} else {
setIconCachePath("");
}
}, [group.icon, group.name]);
useEffect(() => {
initIconCachePath();
}, [initIconCachePath]);
function getFileName(url: string) {
return url.substring(url.lastIndexOf("/") + 1);
}
const iconCachePath = useIconCache({
icon: group.icon,
cacheKey: group.name.replaceAll(" ", ""),
enabled: enable_group_icon,
});
const proxyColItemsMemo = useMemo(() => {
if (type !== 4 || !proxyCol) {

View File

@ -2,15 +2,15 @@ import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { LanguageRounded } from "@mui/icons-material";
import { Box, Divider, MenuItem, Menu, styled, alpha } from "@mui/material";
import { convertFileSrc } from "@tauri-apps/api/core";
import { UnlistenFn } from "@tauri-apps/api/event";
import { useLockFn } from "ahooks";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { BaseLoading } from "@/components/base";
import { useIconCache } from "@/hooks/use-icon-cache";
import { useListen } from "@/hooks/use-listen";
import { cmdTestDelay, downloadIconCache } from "@/services/cmds";
import { cmdTestDelay } from "@/services/cmds";
import delayManager from "@/services/delay";
import { showNotice } from "@/services/notice-service";
import { debugLog } from "@/utils/debug";
@ -46,7 +46,7 @@ export const TestItem = ({
const [position, setPosition] = useState({ left: 0, top: 0 });
const [delay, setDelay] = useState(-1);
const { uid, name, icon, url } = itemData;
const [iconCachePath, setIconCachePath] = useState("");
const iconCachePath = useIconCache({ icon, cacheKey: uid });
const { addListener } = useListen();
const onDelay = useCallback(async () => {
@ -55,24 +55,6 @@ export const TestItem = ({
setDelay(result);
}, [url]);
const initIconCachePath = useCallback(async () => {
if (icon && icon.trim().startsWith("http")) {
const fileName = uid + "-" + getFileName(icon);
const iconPath = await downloadIconCache(icon, fileName);
setIconCachePath(convertFileSrc(iconPath));
} else {
setIconCachePath("");
}
}, [icon, uid]);
useEffect(() => {
void initIconCachePath();
}, [initIconCachePath]);
function getFileName(url: string) {
return url.substring(url.lastIndexOf("/") + 1);
}
const onEditTest = () => {
setAnchorEl(null);
onEdit();

View File

@ -0,0 +1,54 @@
import { convertFileSrc } from "@tauri-apps/api/core";
import { useMemo } from "react";
import useSWR from "swr";
import { downloadIconCache } from "@/services/cmds";
import { SWR_DEFAULTS } from "@/services/config";
export interface UseIconCacheOptions {
icon?: string | null;
cacheKey?: string;
enabled?: boolean;
}
const getFileNameFromUrl = (url: string) => {
const lastSlashIndex = url.lastIndexOf("/");
return lastSlashIndex >= 0 ? url.slice(lastSlashIndex + 1) : url;
};
export const useIconCache = ({
icon,
cacheKey,
enabled = true,
}: UseIconCacheOptions) => {
const iconValue = icon?.trim() ?? "";
const cacheKeyValue = cacheKey?.trim() ?? "";
const swrKey = useMemo(() => {
if (!enabled || !iconValue.startsWith("http") || cacheKeyValue === "") {
return null;
}
return ["icon-cache", iconValue, cacheKeyValue] as const;
}, [enabled, iconValue, cacheKeyValue]);
const { data } = useSWR(
swrKey,
async () => {
try {
const fileName = `${cacheKeyValue}-${getFileNameFromUrl(iconValue)}`;
const iconPath = await downloadIconCache(iconValue, fileName);
return convertFileSrc(iconPath);
} catch {
return "";
}
},
SWR_DEFAULTS,
);
if (!swrKey) {
return "";
}
return data ?? "";
};