πŸ›’ Cart

Learn how to identify and fix one of the most common Blazor performance mistakes using Blazor Developer Tools.

πŸ› The Problem: Unnecessary Re-renders

This is one of the most common performance mistakes Blazor developers make. When a parent component re-renders, all of its child components re-render tooβ€”even if their data hasn't changed.

The Scenario

You have a list of product cards. When you update one product's quantity, what happens to the other cards?

@foreach (var product in Products)
{
    <ProductCard 
        Name="@product.Name"
        Quantity="@product.Quantity"
        QuantityChanged="@HandleChange" />
}
What You Expect

Only the changed product card re-renders.

What Actually Happens

ALL product cards re-render! Even the ones whose data didn't change.

With 10 products and a 50ms render time each, changing one quantity takes 500ms instead of 50ms.

πŸ§ͺ Interactive Demo

πŸ“Š Open Blazor Developer Tools (F12 β†’ Blazor tab) to see real-time metrics. Compare the Render Count between Basic and Optimized cards when you update any in their group. For non-optimized cards, changing quantity in one will re-render all of them. Optimized cards don't re-render unnecessarily.
βš™οΈ Controls
❌ Basic (No Optimization)
🍎
Apples

¤2.99/lb

0
🍊
Oranges

¤3.49/lb

0
🍋
Lemons

¤1.99/lb

0
🍇
Grapes

¤4.99/lb

0

In DevTools: All cards have the same Render Count

βœ… Optimized (With ShouldRender)
🍎
Apples

¤2.99/lb

0
🍊
Oranges

¤3.49/lb

0
🍋
Lemons

¤1.99/lb

0
🍇
Grapes

¤4.99/lb

0

In DevTools: Each card has different Render Count. Check ShouldRender Stats!

πŸ›’ Cart Summary
0 items

Your cart is empty

πŸ” How to Detect This Problem with Blazor Developer Tools

Step 1: Open DevTools

Press F12 and navigate to the Blazor tab in your browser's developer tools.

Step 2: Find Your Components

Look for the component tree. Click on individual ProductCardBasic components.

Step 3: Check the Metrics

Look for these key metrics in the details panel:

  • Render Count - How many times the component rendered
  • Lifecycle Timing β†’ Calls column - Call counts for each lifecycle method
  • ShouldRender Stats β†’ True / False - Renders allowed vs skipped
🚨 Red Flags to Look For
Problem Indicator: Multiple sibling components all have the same Render Count even though only one of them should have changed.
βœ… What Healthy Looks Like
Optimized Indicator: Components have different Render Counts. Unchanged components show increasing False count in ShouldRender Stats.

βœ… The Solution: Override ShouldRender()

Blazor calls ShouldRender() before every render. By default, it returns true. Override it to return false when your component's output wouldn't change.

❌ Before (ProductCardBasic)
@code {
    [Parameter]
    public int Quantity { get; set; }
    
    // No ShouldRender override
    // Component re-renders EVERY time parent does
}
βœ… After (ProductCardOptimized)
@code {
    [Parameter]
    public int Quantity { get; set; }
    
    private int _lastQuantity = -1;
    
    protected override bool ShouldRender()
    {
        // Only render if OUR data changed
        if (Quantity == _lastQuantity)
            return false; // Skip render!
        
        _lastQuantity = Quantity;
        return true;
    }
}
⚠️ Important: Track all parameters that affect your component's output. If you have Name, Price, and Quantity, check all three!

πŸ”¬ Under the Hood: Why Blazor Works This Way

The Render Cycle

When you call StateHasChanged() or a parameter changes, Blazor follows this flow:

  1. Parent calls StateHasChanged() β†’ Parent queued for re-render
  2. Parent's BuildRenderTree runs β†’ Generates new virtual DOM
  3. Blazor diffs the virtual DOM β†’ Finds child components
  4. For each child: SetParametersAsync() β†’ Parameters passed to child
  5. Child's ShouldRender() called β†’ Returns true by default
  6. Child's BuildRenderTree runs β†’ Even if nothing changed!
Why Doesn't Blazor Optimize This Automatically?

Blazor could compare parameters automatically, but:

  • Reference types (objects, lists) are compared by reference, not value
  • Deep comparison is expensive and error-prone
  • You know your component bestβ€”you decide what matters
The Performance Math
Scenario Basic Optimized
4 products, 100ms render 400ms 100ms
20 products, 100ms render 2000ms 100ms
Complexity O(n) O(1)
Other Optimization Strategies
@key Directive

Helps Blazor track list items efficiently during re-ordering.

@foreach (var item in Items)
{ <Item @key="item.Id" /> }
Virtualization

Only render visible items in long lists.

<Virtualize Items="Items">
...</Virtualize>
ImmutableData

Use immutable objects so reference comparison works.

record Product(int Id, string Name);

πŸ“‹ Blazor Developer Tools Workflow

1
Identify

Notice UI sluggishness or check render counts in DevTools

2
Investigate

Compare Render Count across sibling components

3
Implement

Add ShouldRender() to skip unnecessary renders

4
Verify

Confirm False count increases in ShouldRender Stats

An unhandled error has occurred. Reload πŸ—™