Skip to content

ObjectMap's dataConfig pays a JSON.stringify on every render to buy an identity that [schema] already gives for free #6018

Description

@yinlianghui

Measured while implementing #5976 (PR #6016). Out of that card's scope — filing plainly for triage to grade.

What was measured

packages/plugin-map/src/ObjectMap.tsx:588-592, the line immediately above the one #5976 fixed:

constrawDataConfig=getDataConfig(schema);// Memoize dataConfig using deep comparison to prevent infinite loopsconstdataConfig=useMemo(()=>{returnrawDataConfig;},[JSON.stringify(rawDataConfig)]);

getDataConfig(schema) is called bare in the render body — structurally the same shape as the #5976 defect. The difference is where the cost lands: dataConfigdoes end up with a stable identity, so this is not the same bug. It buys that stability by running JSON.stringify over the config on every render, plus a fresh getDataConfig call to feed it.

The reason that mattered is real: dataConfig is a dependency of the fetch effect, which calls setData — a fresh identity there is a re-render loop, not just waste. That is what the "prevent infinite loops" comment records.

Why the serialize now looks unnecessary rather than merely costly

#5976 established, by tracing all three callers, that the schema identity reaching this component is already stable across the renders that matter:

  • SchemaRenderer hands over the memoized evaluatedSchema (SchemaRenderer.tsx:516);
  • ElementDataSourceGate hands over mapped, a React.useMemo in useElementDataSourceSchema;
  • ListView's case 'map' flatten hands over viewComponentSchema, a React.useMemo (ListView.tsx:2007);
  • and every re-render ObjectMap causes itself leaves the prop untouched by construction.

getDataConfig is a pure function of schema and reads nothing else, so

constdataConfig=useMemo(()=>getDataConfig(schema),[schema]);

appears to give the same stable identity the effect needs, with no serialize and no per-render rebuild. That is the shape #5976's fix landed for mapConfig, and its identity test now pins it.

What has NOT been measured, and would need to be before acting

  • Whether the loop the comment guards against is still reachable. The comment predates the caller-side memoization above; it should be confirmed the effect stays quiet under the identity-keyed form rather than assumed. ObjectMap's marker useMemo never memoizes — getMapConfig runs unmemoized in the render body, so mapConfig has a fresh identity every render #5976's pin covers the marker pipeline, not the fetch effect.
  • Whether JSON.stringify is currently masking a false-equal. It is key-order sensitive and drops undefined values, so two semantically different configs can produce the same key (stale — actually wrong, not merely wasteful). I did not find a reachable path: getDataConfig builds its objects with literal key order in every branch, and the one passthrough branch returns the author's own schema.data object, whose key order is fixed per object. Recorded as "not found", not as "cannot happen".

Scope note

Not folded into PR #6016. That PR's claim is narrow — mapConfig's identity — and it deliberately leaves :590 untouched and says so, because this is a different value with a different consumer (an effect, not a derived-value memo) and a genuine loop hazard in its history. Changing it needs its own measurement of that effect.

Unassigned; filed plainly for triage to grade.


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions