diff --git a/src/components/home/system-info-card.tsx b/src/components/home/system-info-card.tsx
index 9a4e170fa..6d93a57b8 100644
--- a/src/components/home/system-info-card.tsx
+++ b/src/components/home/system-info-card.tsx
@@ -7,13 +7,13 @@ import {
} from '@mui/icons-material'
import { Typography, Stack, Divider, Chip, IconButton } from '@mui/material'
import { useLockFn } from 'ahooks'
-import { useCallback, useEffect, useMemo, useReducer } from 'react'
+import { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router'
import { useServiceInstaller } from '@/hooks/use-service-installer'
import { useSystemState } from '@/hooks/use-system-state'
-import { useUpdate } from '@/hooks/use-update'
+import { useUpdate, updateLastCheckTime } from '@/hooks/use-update'
import { useVerge } from '@/hooks/use-verge'
import { getSystemInfo } from '@/services/cmds'
import { showNotice } from '@/services/notice-service'
@@ -21,29 +21,6 @@ import { version as appVersion } from '@root/package.json'
import { EnhancedCard } from './enhanced-card'
-interface SystemState {
- osInfo: string
- lastCheckUpdate: string
-}
-
-type SystemStateAction =
- | { type: 'set-os-info'; payload: string }
- | { type: 'set-last-check-update'; payload: string }
-
-const systemStateReducer = (
- state: SystemState,
- action: SystemStateAction,
-): SystemState => {
- switch (action.type) {
- case 'set-os-info':
- return { ...state, osInfo: action.payload }
- case 'set-last-check-update':
- return { ...state, lastCheckUpdate: action.payload }
- default:
- return state
- }
-}
-
export const SystemInfoCard = () => {
const { t } = useTranslation()
const { verge, patchVerge } = useVerge()
@@ -51,28 +28,18 @@ export const SystemInfoCard = () => {
const { isAdminMode, isSidecarMode } = useSystemState()
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(),
- })
- },
- })
+ // 自动检查更新逻辑(lastCheckUpdate 由 useUpdate 统一管理)
+ const { checkUpdate: triggerCheckUpdate, lastCheckUpdate } = useUpdate(true)
- // 系统信息状态
- const [systemState, dispatchSystemState] = useReducer(systemStateReducer, {
- osInfo: '',
- lastCheckUpdate: '-',
- })
+ const [osInfo, setOsInfo] = useState('')
+
+ const lastCheckUpdateText = useMemo(
+ () => (lastCheckUpdate ? new Date(lastCheckUpdate).toLocaleString() : '-'),
+ [lastCheckUpdate],
+ )
// 初始化系统信息
useEffect(() => {
- let timeoutId: number | undefined
-
getSystemInfo()
.then((info) => {
const lines = info.split('\n')
@@ -87,49 +54,24 @@ export const SystemInfoCard = () => {
sysVersion = sysVersion.substring(sysName.length).trim()
}
- dispatchSystemState({
- type: 'set-os-info',
- payload: `${sysName} ${sysVersion}`,
- })
+ setOsInfo(`${sysName} ${sysVersion}`)
}
})
.catch(console.error)
+ }, [])
- // 获取最后检查更新时间
- const lastCheck = localStorage.getItem('last_check_update')
- if (lastCheck) {
- try {
- const timestamp = parseInt(lastCheck, 10)
- if (!isNaN(timestamp)) {
- dispatchSystemState({
- type: 'set-last-check-update',
- payload: new Date(timestamp).toLocaleString(),
- })
- }
- } catch (e) {
- console.error('Error parsing last check update time', e)
- }
- } else if (verge?.auto_check_update) {
- // 如果启用了自动检查更新但没有记录,设置当前时间并延迟检查
- const now = Date.now()
- localStorage.setItem('last_check_update', now.toString())
- dispatchSystemState({
- type: 'set-last-check-update',
- payload: new Date(now).toLocaleString(),
- })
+ // 如果启用了自动检查更新但没有记录,设置当前时间并延迟检查
+ useEffect(() => {
+ if (!verge?.auto_check_update) return
+ const stored = localStorage.getItem('last_check_update')
+ if (stored) return
- timeoutId = window.setTimeout(() => {
- if (verge?.auto_check_update) {
- triggerCheckUpdate().catch(console.error)
- }
- }, 5000)
- }
- return () => {
- if (timeoutId !== undefined) {
- window.clearTimeout(timeoutId)
- }
- }
- }, [verge?.auto_check_update, dispatchSystemState, triggerCheckUpdate])
+ updateLastCheckTime()
+ const timeoutId = window.setTimeout(() => {
+ triggerCheckUpdate().catch(console.error)
+ }, 5000)
+ return () => window.clearTimeout(timeoutId)
+ }, [verge?.auto_check_update, triggerCheckUpdate])
// 导航到设置页面
const goToSettings = useCallback(() => {
@@ -157,12 +99,6 @@ export const SystemInfoCard = () => {
const onCheckUpdate = useLockFn(async () => {
try {
const info = await triggerCheckUpdate()
- const now = Date.now()
- localStorage.setItem('last_check_update', now.toString())
- dispatchSystemState({
- type: 'set-last-check-update',
- payload: new Date(now).toLocaleString(),
- })
if (!info?.available) {
showNotice.success(
'settings.components.verge.advanced.notifications.latestVersion',
@@ -280,7 +216,7 @@ export const SystemInfoCard = () => {
{t('home.components.systemInfo.fields.osInfo')}
- {systemState.osInfo}
+ {osInfo}
@@ -341,7 +277,7 @@ export const SystemInfoCard = () => {
'&:hover': { opacity: 0.7 },
}}
>
- {systemState.lastCheckUpdate}
+ {lastCheckUpdateText}
diff --git a/src/components/setting/setting-verge-advanced.tsx b/src/components/setting/setting-verge-advanced.tsx
index 625bf3bca..119a023db 100644
--- a/src/components/setting/setting-verge-advanced.tsx
+++ b/src/components/setting/setting-verge-advanced.tsx
@@ -4,6 +4,7 @@ import { useCallback, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { DialogRef, TooltipIcon } from '@/components/base'
+import { updateLastCheckTime } from '@/hooks/use-update'
import {
exitApp,
exportDiagnosticInfo,
@@ -45,6 +46,7 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
const onCheckUpdate = async () => {
try {
const info = await checkUpdate()
+ updateLastCheckTime()
if (!info?.available) {
showNotice.success(
'settings.components.verge.advanced.notifications.latestVersion',
diff --git a/src/hooks/use-update.ts b/src/hooks/use-update.ts
index eb954aee8..16ceed48e 100644
--- a/src/hooks/use-update.ts
+++ b/src/hooks/use-update.ts
@@ -1,4 +1,4 @@
-import useSWR, { SWRConfiguration } from 'swr'
+import useSWR, { mutate as globalMutate, SWRConfiguration } from 'swr'
import { checkUpdateSafe } from '@/services/update'
@@ -12,6 +12,26 @@ export interface UpdateInfo {
downloadAndInstall: (onEvent?: any) => Promise
}
+// --- Last check timestamp (shared via SWR + localStorage) ---
+
+const LAST_CHECK_KEY = 'last_check_update'
+
+const readLastCheckFromStorage = (): number | null => {
+ const stored = localStorage.getItem(LAST_CHECK_KEY)
+ if (!stored) return null
+ const ts = parseInt(stored, 10)
+ return isNaN(ts) ? null : ts
+}
+
+export const updateLastCheckTime = (timestamp?: number): number => {
+ const now = timestamp ?? Date.now()
+ localStorage.setItem(LAST_CHECK_KEY, now.toString())
+ globalMutate(LAST_CHECK_KEY, now, false)
+ return now
+}
+
+// --- useUpdate hook ---
+
export const useUpdate = (
enabled: boolean = true,
options?: SWRConfiguration,
@@ -36,11 +56,26 @@ export const useUpdate = (
refreshInterval: 24 * 60 * 60 * 1000, // 24 hours
dedupingInterval: 60 * 60 * 1000, // 1 hour
...options,
+ onSuccess: (...args) => {
+ updateLastCheckTime()
+ options?.onSuccess?.(...args)
+ },
})
+ // Shared last check timestamp
+ const { data: lastCheckUpdate } = useSWR(
+ LAST_CHECK_KEY,
+ readLastCheckFromStorage,
+ {
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ },
+ )
+
return {
updateInfo,
checkUpdate,
loading: isValidating,
+ lastCheckUpdate: lastCheckUpdate ?? null,
}
}