Measured while verifying #4549 (the slot refreshKey card). Filed separately: it is upstream of that slot and orthogonal to it.
What was measured
Driving renderStudioGridList (the Data pillar's renderListView slot) with a real ListView and a counting dataSource, then forcing three re-renders that change nothing — same refresh signal value, same column names:
t=600ms find=1 (mount settled)
--- 3 rerenders (same counter) ---
t+50ms find=4
One extra find() per render. Re-running the identical harness with the columns array hoisted to a stable identity and changing nothing else:
t=600ms find=1
--- 3 rerenders (same counter) ---
t+300ms find=1
--- bump ---
t++50ms find=2
Zero extra fetches on re-render, and the refresh signal still refetches exactly once. So the trigger is the identity of schema.columns, not its contents.
Why it fires in Studio
ListView derives its expand fields from schema.columns, and that derivation sits in the fetch effect's dependency array by identity (packages/plugin-list/src/ListView.tsx:1609 — expandFields among the deps). A fresh array literal per render therefore re-runs the fetch.
The Studio Data pillar hands it exactly that. packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx:2600 builds the object-view schema inline:
table: {
fields: readFields(objDraft.fields).entries.map(...).filter(...),
},
.map().filter() allocates a new array on every render, plugin-view's ObjectView forwards it to the slot as columns (packages/plugin-view/src/ObjectView.tsx, the renderListView payload), and the slot spreads it into ListView's schema. The Studio grid re-renders constantly (its whole schema is a fresh object literal each time), so this is a steady-state duplicate-query source against the backend, not a rare edge.
Impact
Every keystroke-level re-render of the Data pillar issues another list query. Invisible in the UI — the rows just repaint with the same data — so it reads as "working" while multiplying backend load.
Worth deciding
Two candidate fixes, opposite ends:
- Producer side — memoize the
table.fields array in StudioDesignSurface (React.useMemo keyed on the draft's field names). Narrow, but only fixes this one consumer; any other caller passing a fresh array has the same defect.
- Consumer side — have
ListView depend on the column names' value (a joined key) rather than the array identity. Fixes every caller at once, but it is a plugin-list change and needs care that a genuinely changed column set still refetches.
(2) looks like the real fix, since the identity contract is currently unstated and every caller has to guess it. Someone who owns plugin-list's fetch effect should judge.
Refs #4549, #4528.
Generated by Claude Code
Measured while verifying #4549 (the slot
refreshKeycard). Filed separately: it is upstream of that slot and orthogonal to it.What was measured
Driving
renderStudioGridList(the Data pillar'srenderListViewslot) with a realListViewand a countingdataSource, then forcing three re-renders that change nothing — same refresh signal value, same column names:One extra
find()per render. Re-running the identical harness with thecolumnsarray hoisted to a stable identity and changing nothing else:Zero extra fetches on re-render, and the refresh signal still refetches exactly once. So the trigger is the identity of
schema.columns, not its contents.Why it fires in Studio
ListViewderives its expand fields fromschema.columns, and that derivation sits in the fetch effect's dependency array by identity (packages/plugin-list/src/ListView.tsx:1609—expandFieldsamong the deps). A fresh array literal per render therefore re-runs the fetch.The Studio Data pillar hands it exactly that.
packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx:2600builds the object-view schema inline:.map().filter()allocates a new array on every render, plugin-view's ObjectView forwards it to the slot ascolumns(packages/plugin-view/src/ObjectView.tsx, therenderListViewpayload), and the slot spreads it intoListView's schema. The Studio grid re-renders constantly (its whole schema is a fresh object literal each time), so this is a steady-state duplicate-query source against the backend, not a rare edge.Impact
Every keystroke-level re-render of the Data pillar issues another list query. Invisible in the UI — the rows just repaint with the same data — so it reads as "working" while multiplying backend load.
Worth deciding
Two candidate fixes, opposite ends:
table.fieldsarray inStudioDesignSurface(React.useMemokeyed on the draft's field names). Narrow, but only fixes this one consumer; any other caller passing a fresh array has the same defect.ListViewdepend on the column names' value (a joined key) rather than the array identity. Fixes every caller at once, but it is aplugin-listchange and needs care that a genuinely changed column set still refetches.(2) looks like the real fix, since the identity contract is currently unstated and every caller has to guess it. Someone who owns
plugin-list's fetch effect should judge.Refs #4549, #4528.
Generated by Claude Code