fix(ui): prevent infinite re-render loop in VirtualKeysTable - #25784
fix(ui): prevent infinite re-render loop in VirtualKeysTable#25784Bytechoreographer wants to merge 1 commit into
Conversation
`keys?.keys || []` produces a new array reference on every render when `keys` is undefined (during initial load). The useEffect([keys, filters]) in useFilterLogic treated each new reference as a change, called setFilteredKeys, triggered a re-render, and looped indefinitely. Stabilise the reference with useMemo before passing it to the hook: const keysList = useMemo(() => keys?.keys ?? [], [keys?.keys]); Also add two regression tests in filter_logic.test.tsx that verify the hook does not hang when re-rendered with a new empty-array reference. Co-Authored-By: Claude Sonnet 4 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR stabilizes the Confidence Score: 5/5Safe to merge — the one-line fix is correct and the only finding is a P2 test-coverage observation. No P0/P1 issues. The No files require special attention.
|
| Filename | Overview |
|---|---|
| ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.tsx | Adds useMemo to stabilize the keys?.keys reference before passing it to useFilterLogic, correctly breaking the render-loop feedback cycle. |
| ui/litellm-dashboard/src/components/key_team_helpers/filter_logic.test.tsx | Adds two regression tests; the first test does not reproduce the actual feedback-cycle infinite loop (it only exercises explicit rerenders, not the state-driven component re-render that triggers the real bug). |
Sequence Diagram
sequenceDiagram
participant VKT as VirtualKeysTable
participant UFL as useFilterLogic
note over VKT,UFL: Before fix - infinite loop while keys is loading
VKT->>UFL: keys?.keys || [] (new ref every render)
UFL->>UFL: useEffect fires (ref changed)
UFL->>UFL: setFilteredKeys([])
UFL-->>VKT: state update triggers re-render
VKT->>UFL: keys?.keys || [] (another new ref)
note over VKT,UFL: loop repeats indefinitely
note over VKT,UFL: After fix - useMemo breaks the cycle
VKT->>VKT: useMemo returns stable [] ref
VKT->>UFL: keysList (stable ref)
UFL->>UFL: useEffect fires once
UFL->>UFL: setFilteredKeys([])
UFL-->>VKT: state update triggers re-render
VKT->>VKT: useMemo returns same [] ref (no change)
VKT->>UFL: keysList (same ref - effect does not re-fire)
Reviews (1): Last reviewed commit: "fix(ui): prevent infinite re-render loop..." | Re-trigger Greptile
PR: fix(ui): prevent infinite re-render loop in VirtualKeysTable
Relevant issues
Pre-Submission checklist
ui/litellm-dashboard/src/components/key_team_helpers/filter_logic.test.tsxnpm run testpasses for affected files (34/34)@greptileaion the PR and get Confidence Score ≥ 4/5 before requesting maintainer reviewType
🐛 Bug Fix
Changes
Root cause
VirtualKeysTable.tsxpassedkeys?.keys || []directly intouseFilterLogic:While
keysis loading (keys?.keysisundefined), the|| []fallbackproduces a new array reference on every render. The
useEffect([keys, filters])inside
useFilterLogictreats each new reference as a change, callssetFilteredKeys, which triggers a re-render, which produces another new[]…resulting in an infinite loop.
In development mode this surfaces as:
In the production build React's production runtime silences the warning, but
the excess re-renders still occur on every page load.
Fix
Stabilise the reference with
useMemobefore passing it to the hook(
VirtualKeysTable.tsx):useMemoreturns the same[]across renders untilkeys?.keysactuallychanges, breaking the loop.
??is used instead of||to correctly handlenullas well asundefined.Files changed
ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.tsxuseMemoto stabilisekeysreferenceui/litellm-dashboard/src/components/key_team_helpers/filter_logic.test.tsxTests added (
filter_logic.test.tsx)should not enter an infinite render loop when keys prop is re-rendered with a new empty-array reference|| []pattern: callsrerender({ keys: [] })three times; the hook must complete without hangingshould update filteredKeys when keys prop changes from empty to populatedfilteredKeyscorrectly reflects new data whenkeystransitions from[]to a populated array