fix(ui): prevent infinite re-render loop in VirtualKeysTable - #26601
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>
Greptile SummaryThis PR fixes an infinite re-render loop in Confidence Score: 4/5Safe to merge — the fix is minimal, correct, and well-scoped; only a test coverage gap remains. The No files require special attention.
|
| Filename | Overview |
|---|---|
| ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.tsx | Wraps keys?.keys in useMemo to stabilise the array reference passed to useFilterLogic, correctly breaking the infinite render loop triggered by ` |
| ui/litellm-dashboard/src/components/key_team_helpers/filter_logic.test.tsx | Adds two regression tests for useFilterLogic stability; tests validate hook isolation but don't fully exercise the consumer-side useMemo fix that breaks the actual render loop. |
Sequence Diagram
sequenceDiagram
participant VKT as VirtualKeysTable
participant useMemo
participant UFL as useFilterLogic (useEffect)
participant State as filteredKeys state
Note over VKT,State: BEFORE fix — infinite loop while keys is loading
VKT->>UFL: keys = [] (ref A, new literal)
UFL->>State: setFilteredKeys([])
State-->>VKT: re-render triggered
VKT->>UFL: keys = [] (ref B, new literal)
UFL->>State: setFilteredKeys([])
State-->>VKT: re-render triggered
Note over VKT: Maximum update depth exceeded
Note over VKT,State: AFTER fix — loop broken by useMemo
VKT->>useMemo: keys?.keys = undefined
useMemo-->>VKT: stable [] (ref A, same reference)
VKT->>UFL: keys = [] (ref A)
UFL->>State: setFilteredKeys([])
State-->>VKT: re-render triggered
VKT->>useMemo: keys?.keys = undefined (unchanged)
useMemo-->>VKT: stable [] (ref A, same reference)
VKT->>UFL: keys = [] (ref A, no change)
Note over UFL: useEffect skips — deps unchanged
Reviews (1): Last reviewed commit: "fix(ui): prevent infinite re-render loop..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
@yassin-berriai @mateo-berri @Sameerlite could you take a look when you have a moment?
Small fix for a real perf and usability bug. Would appreciate a merge |
…resolve/virtual-keys # Conflicts: # ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.tsx
|
|
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