Skip to content

perf(metrics): stop re-rendering unchanged metric panels on URL changes - #126977

Merged
JoshuaKGoldberg merged 19 commits into
masterfrom
joshgoldberg/logs-1035-reduce-lag-when-expanding-or-collapsing-metrics
Oct 29, 2026
Merged

JoshuaKGoldberg merged 19 commits into
masterfrom
joshgoldberg/logs-1035-reduce-lag-when-expanding-or-collapsing-metrics

Conversation

@JoshuaKGoldberg

@JoshuaKGoldberg JoshuaKGoldberg commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Problem: Expanding or collapsing a metric panel writes to the URL. Every panel re-decoded its query params from the URL, and table rows and cells subscribed to the location for their links. So any expansion/collapse -> causes a URL change -> causes every component in every other panel to re-render.

This PR fixes it with a few things:

  • Sample rows only read the location in their trace link cell, and Explore field cells keep their cell action menus out of location-driven re-renders.
  • Embedded sample tables keep their rows memoized even when their query is disabled.
  • Button tracking also returns a stable function

As part of this I extracted renderTraceCell out into a TraceLinkCell component.

Keeping unchanged panels' query params and mutators stable is split out into #128357.

Together with getsentry/sentry-javascript#25336 I think this should fix much of the perf issues around metrics panel toggles.

Collapsing one of three metric panels (median of 12) Prod This PR's preview Delta
Main-thread busy time 159ms 128ms −20%
Components re-rendered 9,894 1,839 −81%
React commits 7 4 −43%

Closes LOGS-1035.

Expanding or collapsing a metric writes to the URL, which re-rendered
every sample table row in every panel because rows read the location
for their trace links. Memoize the rows and pass them a stable,
metric-param-stripped location instead.

Fixes LOGS-1035
@linear-code

linear-code Bot commented Oct 8, 2026

Copy link
Copy Markdown

LOGS-1035

@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Oct 8, 2026
@JoshuaKGoldberg JoshuaKGoldberg changed the title perf(metrics): Stop re-rendering unchanged sample rows on URL changes perf(metrics): stop re-rendering unchanged sample rows on URL changes Oct 13, 2026
BaseExploreFieldRenderer read the location and route for its links, so every Explore table cell re-rendered its action menu, buttons, and tooltip on any URL change. A child component now reads them for the cell value alone.

Refs LOGS-1035
…L changes

The button tracking hooks returned a new function on every render, so each navigation changed the tracking context and re-rendered every Button and Link. The starred Explore queries list also rebuilt on any query param change, though it only reads the query id and pathname.

Refs LOGS-1035
This reverts commit f412c68. The cells kept re-rendering through the per-panel query params context, so moving the location read into a child had no measurable effect.

Refs LOGS-1035
Its links subscribe to the location themselves, so they kept re-rendering and the memo saved almost nothing.

Refs LOGS-1035
… changes

Every URL change re-decoded every metric query and rebuilt each row's mutators, so every panel's query params context changed and re-rendered its charts, toolbars, and table cells. Decoded queries are now reused for unchanged URL values, and each row gets stable mutators.

Refs LOGS-1035
Restores f412c68. Now that unchanged metric panels keep stable query params, the location read was the last thing re-rendering each cell's action menu, buttons, and tooltip.

Refs LOGS-1035
@JoshuaKGoldberg JoshuaKGoldberg changed the title perf(metrics): stop re-rendering unchanged sample rows on URL changes perf(metrics): stop re-rendering unchanged metric panels on URL changes Oct 13, 2026
…035-reduce-lag-when-expanding-or-collapsing-metrics

# Conflicts:
#	static/app/views/explore/metrics/metricInfoTabs/metricsSamplesTableRow.tsx
@JoshuaKGoldberg

Copy link
Copy Markdown
Member Author

@cursor review

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread static/app/views/explore/metrics/useMetricQueriesController.tsx Outdated
Comment thread static/app/views/explore/metrics/multiMetricsQueryParams.tsx Outdated
…ut effects

The stable row mutators read rows that a layout effect updated, but descendant layout effects run first. A group by cleanup in the same commit as a query change could write stale rows to the URL and revert that change. An insertion effect updates them before any layout effect runs.

Refs LOGS-1035
…anels

Panels with identical URL values received the same decoded query objects, so an in-place change to one would leak into the other. The cache is now keyed by panel position too. Also adds a regression test for the stale mutator fix.

Refs LOGS-1035
@JoshuaKGoldberg

Copy link
Copy Markdown
Member Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 55ecb2c. Configure here.

@JoshuaKGoldberg
JoshuaKGoldberg marked this pull request as ready for review October 14, 2026 14:20
@JoshuaKGoldberg
JoshuaKGoldberg requested review from a team as code owners October 14, 2026 14:20

@nsdeschenes nsdeschenes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ... tho i had to read up on useInsertionEffect to refresh my memory.

…test ref

The tracker only needs the parameterized route path, which is a string that stays equal across query changes, so it can be a plain useCallback dependency.
Keeping unchanged panels' queries and mutators stable needed a ref synced in an insertion effect. The follow-up does it with updater-based setters instead.
…035-reduce-lag-when-expanding-or-collapsing-metrics

# Conflicts:
#	static/gsApp/overrides/useButtonTracking.spec.tsx
…isabled

The default meta object was recreated each render, so embedded tables rebuilt their memoized meta and re-rendered every row.
… changes (#128357)

Unchanged metric panels now keep the same query params and mutators when
another panel changes, because row mutators hand updater functions to
`setQueries` instead of closing over the rendered queries.

This is done by:

* Switching row mutator updater functions to `setQueries`
* Moving the URL-backed provider onto `nuqs` and its nice stable setter
* Binding each row's mutators to a stable row id, so a mutator held
across another row's removal still edits its own row
* Resetting `nuqs`'s global URL update queue between tests in the shared
test adapter

Rapid edits now coalesce into a single history entry, since `nuqs`
batches URL writes.

Split out of #126977 so we don't have to use esoteric React hooks.
Thanks for prodding me on the docs @nsdeschenes 😄
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

📊 Type Coverage Diff

Metric Before After Delta
Coverage 95.78% 95.78% ±0%
Typed 141,473 141,521 🟢 +48
Untyped 6,227 6,229 🔴 +2
🔍 2 new type safety issues introduced

Non-null assertions (!) (2 new)

File Line Detail
static/app/views/explore/metrics/multiMetricsQueryParams.tsx 118 decodedMetricQueries.keys().next().value!
static/app/views/explore/metrics/useMetricQueriesController.tsx 221 rowMutators[i]!

This is informational only and does not block the PR.

…035-reduce-lag-when-expanding-or-collapsing-metrics

# Conflicts:
#	static/app/scrapsProviders/tracking.tsx
#	static/gsApp/overrides/useButtonTracking.spec.tsx
@sentry

sentry Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Sentry Snapshot Testing

Name Added Removed Changed Renamed Unchanged Skipped Status
sentry-frontend
sentry-frontend
- - - - - - ✅ 760 uploaded

Base commit 65ab0d9579234f7b0097bf5903e141193409a5fa did not produce snapshots to compare against. Did its snapshot job fail? Try rebasing this branch on a commit with a successful snapshot job.

⚙️ sentry-frontend Snapshot Settings

@JoshuaKGoldberg

Copy link
Copy Markdown
Member Author

@nsdeschenes I ended up refactoring a bunch to not use weird hooks!

@JoshuaKGoldberg
JoshuaKGoldberg merged commit ef1bb91 into master Oct 29, 2026
84 of 85 checks passed
@JoshuaKGoldberg
JoshuaKGoldberg deleted the joshgoldberg/logs-1035-reduce-lag-when-expanding-or-collapsing-metrics branch October 29, 2026 14:31
JoshuaKGoldberg added a commit that referenced this pull request Oct 29, 2026
)

Fixes the frontend build on master after #126977.

That PR moved the value rendering out of `BaseExploreFieldRenderer` and
into a new `ExploreFieldValue` component. Meanwhile, a separate change
landed that reads a per-query `caseInsensitive` prop. After the two
merged, `ExploreFieldValue` still referenced `queryCaseInsensitive`, but
that variable only exists in the parent's props. This broke `tsc` and
threw `ReferenceError: queryCaseInsensitive is not defined` in Jest
across the explore and metrics specs.

This PR passes the prop down to `ExploreFieldValue`. When a query sets a
value, it still wins over the page-level case-insensitivity setting.

<!-- junior-request-attribution:start -->
via **Josh Goldberg**.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:slack%3AC8V02RHC7%3A1793284533.806639 -->

--

[View Junior
Session](https://junior-prod.sentry.dev/conversations/slack%3AC8V02RHC7%3A1793284533.806639)
[[Sentry]](https://sentry.sentry.io/explore/conversations/slack%3AC8V02RHC7%3A1793284533.806639/?project=4510944073809921)

<!-- junior-session-footer:end -->

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: Josh Ghoulberg <joshua.goldberg@sentry.io>

This branch was successfully deployed

1 active deployment
Preview — 7deab492 Deployed Oct 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants