UpdateThrottled

Throttle high-frequency state updates to improve performance and prevent overwhelming your UI with rapid changes.

What is UpdateThrottled?

UpdateThrottled limits how frequently state updates can occur. Instead of processing every single event (like mouse movements or scroll events), it ensures updates happen at most once per specified interval.

Code Reduction: 95%

From 22 lines of manual throttle logic down to 1 line. No timers, no state tracking, no cleanup.

Throttle vs Debounce

UpdateThrottled

  • When it updates: Immediately, then at most once per interval
  • Behavior: Guarantees regular updates during activity
  • Use for: Mouse tracking, scroll events, resize handlers
  • Example: Update position every 100ms while mouse is moving

UpdateDebounced

  • When it updates: After activity stops for specified delay
  • Behavior: Waits for pause before updating
  • Use for: Search input, form validation, auto-save
  • Example: Search 300ms after user stops typing

Before & After

Before: Manual Throttle Logic (22 lines)

private DateTime? _lastUpdate;
private readonly TimeSpan _throttleInterval = TimeSpan.FromMilliseconds(100);
private object _lock = new object();

void OnMouseMove(MouseEventArgs e)
{
    lock (_lock)
    {
        var now = DateTime.UtcNow;

        if (_lastUpdate.HasValue)
        {
            var elapsed = now - _lastUpdate.Value;
            if (elapsed < _throttleInterval)
            {
                return; // Ignore this update
            }
        }

        _lastUpdate = now;
        await Update(s => s.SetPosition(e.ClientX, e.ClientY));
    }
}

After: UpdateThrottled (1 line)

<div @onmousemove="@(e => UpdateThrottled(s => s.SetPosition(e.ClientX, e.ClientY), 100))">
    Mouse tracker
</div>

Example: Mouse Position Tracking

Track mouse position without overwhelming your UI with updates on every pixel movement.

State.cs
public record MouseState(int X, int Y)
{
    public static MouseState Initial => new(0, 0);

    public MouseState SetPosition(int x, int y) =>
        this with { X = x, Y = y };
}
MouseTracker.razor
@page "/mouse"
@inherits StoreComponent<MouseState>

<div class="tracker-container"
     @onmousemove="@(e => UpdateThrottled(s => s.SetPosition((int)e.ClientX, (int)e.ClientY), 100))">
    <h2>Mouse Position</h2>
    <p>X: @State.X</p>
    <p>Y: @State.Y</p>
    <p class="hint">Move your mouse around (updates max 10x/second)</p>
</div>

<style>
    .tracker-container {
        height: 400px;
        border: 2px solid #ccc;
        padding: 20px;
    }
</style>
Performance Impact

Without throttling: ~1000 updates/second (browser maximum)
With 100ms throttle: ~10 updates/second
Result: 99% reduction in updates, smooth UX maintained

Example: Scroll Position Tracking

Track scroll position efficiently without processing every single scroll event.

State.cs
public record ScrollState(int ScrollTop, bool ShowBackToTop)
{
    public static ScrollState Initial => new(0, false);

    public ScrollState UpdateScroll(int scrollTop) =>
        this with {
            ScrollTop = scrollTop,
            ShowBackToTop = scrollTop > 300
        };
}
ScrollTracker.razor
@page "/scroll"
@inherits StoreComponent<ScrollState>

<div class="content"
     @onscroll="@(e => UpdateThrottled(s => s.UpdateScroll(GetScrollTop(e)), 100))">
    <!-- Long content here -->
</div>

@if (State.ShowBackToTop)
{
    <button class="back-to-top" @onclick="ScrollToTop">
        ↑ Back to Top
    </button>
}

@code {
    int GetScrollTop(EventArgs e)
    {
        // Get scroll position from element
        return State.ScrollTop; // Simplified
    }

    void ScrollToTop()
    {
        // Scroll logic here
    }
}

Common Use Cases

Mouse/Touch Tracking

@onmousemove="@(e => UpdateThrottled(
    s => s.SetPosition(e.ClientX, e.ClientY),
    100))"

Update position max 10 times/second

Scroll Events

@onscroll="@(e => UpdateThrottled(
    s => s.UpdateScroll(),
    100))"

Track scroll without performance hit

Window Resize

@onresize="@(e => UpdateThrottled(
    s => s.SetDimensions(e.Width, e.Height),
    200))"

Update layout max 5 times/second

Live Data Updates

void OnDataReceived(Data data)
{
    UpdateThrottled(s => s.AddData(data), 500);
}

Limit UI updates from real-time streams

API Reference

Method Signature
protected Task UpdateThrottled(
    Func<TState, TState> updater,
    int intervalMs,
    string? action = null)

Parameters

Parameter Type Description
updater Func<TState, TState> State transformation function
intervalMs int Minimum milliseconds between updates
action string? Optional action name for DevTools/logging
Important Notes
  • First call executes immediately
  • Subsequent calls are throttled to the interval
  • Each instance tracks its own throttle state
  • Interval resets after quiet period

Best Practices

✅ Do

  • Use for high-frequency events (mouse, scroll, resize)
  • Choose interval based on human perception (~100ms is good)
  • Use for real-time data streams with frequent updates
  • Combine with selectors for optimal performance
// ✅ Good: Reasonable interval
UpdateThrottled(s => s.Track(x, y), 100)

// ✅ Good: Named action for debugging
UpdateThrottled(s => s.Update(), 100, "SCROLL")

❌ Don't

  • Don't use for user input that needs immediate feedback
  • Don't set interval too low (defeats the purpose)
  • Don't use for infrequent events (button clicks)
  • Don't confuse with debounce (different use cases)
// ❌ Bad: Button click doesn't need throttle
@onclick="@(() => UpdateThrottled(s => s.Click(), 100))"

// ❌ Bad: Interval too low
UpdateThrottled(s => s.Update(), 10) // Almost no throttling

// ❌ Bad: Use debounce for search instead
<input @oninput="@(e => UpdateThrottled(...))" />

Choosing the Right Interval

16-33ms (30-60 FPS)

Use for: Smooth animations, game-like interactions

Examples: Canvas drawing, drag-and-drop with visual feedback

100ms (10 FPS)

Use for: Mouse tracking, scroll position, live dashboards

Examples: Cursor followers, scroll progress indicators

200-500ms (2-5 FPS)

Use for: Window resize, data polling, analytics

Examples: Responsive layouts, chart updates, metrics collection

1000ms+ (1 FPS or less)

Use for: Background updates, heartbeat checks

Examples: Status polling, keep-alive pings

Setup

UpdateThrottled is part of the utility services. Make sure you register them:

Program.cs
// Option 1: All-in-one registration (recommended)
builder.Services.AddStoreWithUtilities(
    new MouseState(),
    (store, sp) => store.WithDefaults(sp, "Mouse"));

// Option 2: Manual registration
builder.Services.AddStoreUtilities();  // Includes throttle manager
builder.Services.AddStore(
    new MouseState(),
    (store, sp) => store.WithDefaults(sp, "Mouse"));

Next Steps