Skip to content

Scenario · Rendering

Dashboard

A realistic component hierarchy: stat cards under a cascading value, a live clock, a user profile and the recent orders loaded over HTTP. It is where the component tree, the cause of every render and the most common avoidable cost in a Blazor app - renders driven only by a parent - are easiest to see.

The dashboard

Plain application code, with one problem left in on purpose: tick clock re-renders whole dashboard and the clock's timer calls StateHasChanged on the whole page twice a second.

Live Renderer: Static · prerendering CtrlShiftD opens BevTools

Revenue

$128,430
+4.2% · settings v0

Orders

1204
+12 · settings v0

Visitors

48,213
-1.8% · settings v0

Server time

15:43:48.5
ticks every 500 ms (StateHasChanged from a timer)

User profile

Ada Lovelace (ada.lovelace)
loading profile…

The access token, api key and the Bearer header are redacted in BevTools (Components → State / Network → headers).

Recent orders (HTTP, 1.2–2.6 s server delay)

loading…

Components: the tree and the inspector

Open BevTools (CtrlShiftD) on the Components tab. Dashboard sits under the site's layouts (Routes → MainLayout → DocsLayout) with its children: three StatsCards, LiveClock, UserProfile and RecentOrders. Each row says how many times the component rendered and how long its last render took; ⚡ on Routes marks where the interactive render mode starts, with the runtime this visit got (Server or WASM).

  • Select a StatsCard: its Parameters (Title, Value, Trend), the cascading DashboardSettings it reads, and under Rendering the cause of every render it has had (Why did it render?, then Recent renders with the batch of each).
  • The same inspector answers where and when: Type & source links StatsCard.razor (it opens in your editor) and names the render mode it inherits and from whom; Lifecycle says when it was created, initialized and first and last rendered, whether a render is queued, and what its SetParametersAsync costs per type.
  • Select UserProfile and expand Session under Injected services: its UserSession shows AccessToken and Nickname redacted - one by its name, the other by [BevToolsSensitive] - and does not list SupportNotes at all, which is marked [BevToolsIgnore].
  • Press Toggle dense or Change accent: the cascading value changes and every card that reads it renders again.

Components in the page: pick, outline, flash

The tree and the page point at each other. BevTools follows Blazor's own record of which component rendered which part of the page, so nothing has to be added to the markup.

  • Press ⌖ Pick in the panel header (or >pick in CtrlK), hover the page - each component is outlined with its name - and click the clock: the inspector opens on LiveClock. Esc cancels.
  • Hover a row of the tree and its component is outlined in the page; ⌖ Show in page in the inspector scrolls to it first.
  • Tick flash renders in the Components toolbar, then tick clock re-renders whole dashboard: every card flashes twice a second. The colour counts the renders since the previous flash: blue once, green 2-3, amber 4-9, red 10 or more.

Profiler and Diagnostics: renders nobody asked for

Tick the checkbox, then open the Profiler and sort by renders: Dashboard and every card climb together. Selected in the inspector, the Revenue card says Parent Dashboard re-rendered (parameters re-applied) and marks those renders forced, because none of its parameter values changed - unlike the Visitors card, whose Value does. Diagnostics reports Renders driven only by the parent for the cards, the three of them as one finding.

State, Network and Services

  • State → AppState: every press of Click counter is a named Click change, and every navigation a Visit. Its ApiKey is redacted.
  • Network: GET /api/orders, slow on purpose, and GET /api/profile, whose Authorization header is redacted. No click sent them, so the Trigger column names the component method that did: from RecentOrders.Reload, from UserProfile.OnAfterRenderAsync.
  • Services: every registration with its lifetime, implementation and how many services it depends on and is used by. Search LeakyCache and ReportService and select them: the dependency tree shows a singleton capturing a scoped service and a circular dependency, registered in this app and never resolved. Diagnostics lists both.

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.

An unhandled error has occurred. Reload 🗙