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.
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.
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 };
}
@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>
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.
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
};
}
@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
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 |
- 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:
// 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"));