perf(analytics): project minimal columns in GetStats/GetAnalyticsOverview #3
@@ -5,6 +5,7 @@
|
|||||||
## Changes made (this pass)
|
## Changes made (this pass)
|
||||||
| Change | File | Effect | Verified |
|
| Change | File | Effect | Verified |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|
| **Stop an infinite render loop on every list view** — hold `load` in a ref in `useViewResource` so `reload`/the fetch effect keep a stable identity | `job-tracker-ui/src/hooks/useViewResource.ts` | Fixes "Maximum update depth exceeded" on `/jobs` (and any `DashboardView`/`RemindersView`/`CompaniesTable` view whose caller passes an inline `load`) — pegged the CPU/renderer | **Runtime-confirmed**: `/jobs` went from a render storm (renderer frozen, 100s of errors) to 0 console errors in a live 2s window and a clean render; `workflow-trust-signals` (drives `JobTable`→`useViewResource`) passes |
|
||||||
| **Stop the infinite `/auth/me` request loop** — make `clearAuthClientState` emit `auth-changed` only on a real signed-in→out transition | `job-tracker-ui/src/auth.ts` | Eliminates a runaway request storm (100+ `GET /auth/me` and climbing) that ran continuously whenever the user was logged out | **Runtime-confirmed** in a live stack: `/auth/me` count 100+ & growing → 0 and stable after fix |
|
| **Stop the infinite `/auth/me` request loop** — make `clearAuthClientState` emit `auth-changed` only on a real signed-in→out transition | `job-tracker-ui/src/auth.ts` | Eliminates a runaway request storm (100+ `GET /auth/me` and climbing) that ran continuously whenever the user was logged out | **Runtime-confirmed** in a live stack: `/auth/me` count 100+ & growing → 0 and stable after fix |
|
||||||
| Revoke CV-preview blob URLs on unmount only (ref-based), not on every carousel change | `job-tracker-ui/src/pages/ProfilePage.tsx` | Fixes broken previews on multi-template decks; still frees URLs on unmount | `profile-page.test.tsx` 5/5 |
|
| Revoke CV-preview blob URLs on unmount only (ref-based), not on every carousel change | `job-tracker-ui/src/pages/ProfilePage.tsx` | Fixes broken previews on multi-template decks; still frees URLs on unmount | `profile-page.test.tsx` 5/5 |
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,17 @@ export function useViewResource<T>(
|
|||||||
hasLoadedRef.current = hasLoaded;
|
hasLoadedRef.current = hasLoaded;
|
||||||
}, [hasLoaded]);
|
}, [hasLoaded]);
|
||||||
|
|
||||||
|
// Hold `load` in a ref so `reload` (and the fetch effect that depends on it)
|
||||||
|
// keep a stable identity across renders. Callers routinely pass an inline
|
||||||
|
// `load` closure; if `load` were a dependency, every render would create a new
|
||||||
|
// `reload`, re-run the effect, setState, and re-render — an infinite loop
|
||||||
|
// ("Maximum update depth exceeded"). Re-fetching is driven by `deps`/`enabled`
|
||||||
|
// instead, and the ref always points at the latest closure.
|
||||||
|
const loadRef = useRef(load);
|
||||||
|
useEffect(() => {
|
||||||
|
loadRef.current = load;
|
||||||
|
});
|
||||||
|
|
||||||
const reload = useCallback(async () => {
|
const reload = useCallback(async () => {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
|
|
||||||
@@ -77,7 +88,7 @@ export function useViewResource<T>(
|
|||||||
setLoading(!alreadyLoaded);
|
setLoading(!alreadyLoaded);
|
||||||
setRefreshing(alreadyLoaded);
|
setRefreshing(alreadyLoaded);
|
||||||
try {
|
try {
|
||||||
const next = await load();
|
const next = await loadRef.current();
|
||||||
setData(next);
|
setData(next);
|
||||||
setError(null);
|
setError(null);
|
||||||
setHasLoaded(true);
|
setHasLoaded(true);
|
||||||
@@ -88,7 +99,7 @@ export function useViewResource<T>(
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
}
|
}
|
||||||
}, [enabled, errorMessage, load]);
|
}, [enabled, errorMessage]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
|
|||||||
Reference in New Issue
Block a user