WebSocket hooks (use-connection-data, use-log-data)
- Single-pass merge for connection snapshots; reuse previous row reference
when upload/download are unchanged so downstream memos can bail out
- Single-allocation cap on closedConnections (no double concat+slice)
- Single-allocation clamp in appendLogs
- Cache dayjs().format result within each 50ms log flush window
Connection table (connection-table.tsx)
- Decouple 5s relative-time tick from columnDefs via shared module-level
tickStore + memoised RelativeTimeCell so the tick no longer rebuilds
the table
- RowComponent memo with custom comparator (relies on stable row reference)
- Lift sx objects to module scope
- Stable onShowDetail via ref
App data provider (app-data-provider, app-data-context)
- Split monolithic context into six sub-contexts (Proxies/Rules/ClashConfig/
System/Uptime/Refreshers); 3s uptime ticks no longer invalidate unrelated
consumers
- useAppData adapter aggregates sub-contexts; consumer files unchanged
- useStableFn helper stabilises all refresh* callback identities
- Extract useCtx helper to remove repeated null-check boilerplate
Canvas traffic graph (enhanced-canvas-traffic-graph, use-traffic-monitor)
- Lift Y-axis scale (max/min) to drawGraph layer; calculateY allocations
per frame: ~600 -> 1
- Document visibility gate stops RAF and the setNow interval when the
window is hidden; appendData unaffected
- Reuse the existing visibilitychange listener instead of adding a second
one; isDocumentVisibleRef guards animate() inside the frame
- Convert forEach arrow shorthands to block bodies
- Drop unnecessary state-setter deps from a useCallback
Proxy groups (proxy-groups, proxy-render, use-render-list)
- Narrow proxyColItemsMemo dep: headState -> headState.showType
- Per-group fingerprint cache + prevListRef in use-render-list; steady-state
refetch ticks become O(0) and the list reference stays stable when nothing
changed
- useStableCallback wraps handleCheckAll / handleLocation
- Extract shared delay state logic from ProxyItem and ProxyItemMini
into `useProxyDelayState` hook (src/hooks/use-proxy-delay-state.ts);
JSX display thresholds preserved per-component.
- Deduplicate rAF/setTimeout/Promise scheduling in DelayManager via
a private `scheduleOnNextFrame` helper.
- Drop no-op `useMemo(() => MODES, [])` in proxies page.
- Replace `any` on `setClashLog` prev params and layout-traffic sx
objects with proper types (`pre!`, `Pick<BoxProps|...>`).
The MUI v9 migration moved boxStyle layout props into sx, but the memory
usage Box had a separate sx that overwrote it. Merge boxStyle.sx like the
upload/download rows already do.
- 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
- Dispose Monaco editor instances on dialog close to prevent cycle leak
- Replace gcTime: Infinity with finite TTLs and evict orphaned subscription queryKeys
- Add missing useEffect cleanup for timers, move setTimeout out of useMemo
Replace swr with @tanstack/react-query v5 across all hooks, providers,
and components. Introduce singleton QueryClient, WS subscription pattern
via useQuery+useEffect, and enforce component-layer cache access contract.
- Remove unused `dns_settings_enabled` localStorage writes in
setting-clash.tsx — state is sourced from verge config, these
writes were never read anywhere.
- Replace hardcoded `'last_check_update'` localStorage read in
system-info-card.tsx with exported `readLastCheckTime()` from
the useUpdate hook, keeping the key in a single source of truth.
The settings page "Check for updates" did not update the homepage
"last check update time" because each page managed the timestamp
independently. Centralizes the timestamp in the useUpdate hook
via SWR + localStorage so both pages share a single data source.
Closes https://github.com/clash-verge-rev/clash-verge-rev/issues/6605#issuecomment-4147144987
The profile-update-completed event handler was missing a mutate('getProfiles')
call, causing the "X time ago" display to show stale timestamps after
backend timer auto-updates.
* fix(proxy): resolve system proxy toggle stuck and state desync (#6614)
Backend: replace hand-rolled AtomicBool lock in update_sysproxy() with
tokio::sync::Mutex so concurrent calls wait instead of being silently
dropped, ensuring the latest config is always applied.
Move blocking OS calls (networksetup on macOS) to spawn_blocking so
they no longer stall the tokio worker thread pool.
Frontend: release SwitchRow pendingRef in .finally() so the UI always
re-syncs with the actual OS proxy state, and rollback checked on error.
Closes#6614
* fix(changelog): add note for macOS proxy toggle freeze issue
The onCheckUpdate handler never persisted the timestamp to localStorage
or dispatched it to component state, so clicking "Last Check Update"
would report the result but leave the displayed time stale.
* chore(deps): update npm dependencies to v8
* build(vite)!: migrate to Vite 8, switch to Oxc-based @vitejs/plugin-react, and clean up legacy compatibility config
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Slinetrac <realakayuki@gmail.com>
* fix: displays rule lineNo instead of index in rule page (#6230)
* fix(rules): derive line numbers in view model without mutating shared rules
* doc: update changelog
---------
Co-authored-by: Slinetrac <realakayuki@gmail.com>
* refactor(ip-info-card): reduce retry, use succeed as lastFetchTs
* refactor(ip-info-card): stop countdown during revalidation
* perf(ip-info-card): avoid aggressive schedule revalidation
* perf(ip-info-card): try stop interval on window minimized
* perf(ip-info-card): only mutate after card scroll into view once
* perf(ip-info-card): interval only when card has been visible
* chore: add more debug information
* Update src/components/home/ip-info-card.tsx
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: reset countdown state after mutate finishes
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* perf(ip-info-card): make ip info card much better
* fix(ip-info-card): remove unused useEffect deps
* Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* refactor(ip-info-card): use `async-retry`, bail out non-2XX resp
* feat(ip-info-card): add new backend
* feat(ip-info-card): only revalidate when window is visible
* perf(ip-info-card): reduce re-renders when window is hidden
* fix(ip-info-card): remove `mutate` from `useEffect` arg
* Update src/components/home/ip-info-card.tsx
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: drop AbortSignal.timeout for old safati compat
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>