Async Helpers Overview
Eliminate 74% of async boilerplate with built-in helpers that transform tedious patterns into one-liners!
What Are Async Helpers?
Async helpers are production-ready utilities that eliminate common boilerplate patterns in async state management. Instead of writing repetitive code for timers, loading states, error handling, throttling, and caching, you get concise, readable one-liners.
These helpers are built directly into StoreComponent<T>, so they're available immediately when you inherit from the base component.
Available Helpers
All five helpers provide significant code reductions while improving readability and maintainability:
| Helper | Eliminates | Code Reduction | Use Case |
|---|---|---|---|
| UpdateDebounced | Timer management (17 lines → 1 line) | 94% | Search inputs, form validation |
| AsyncData<T> | Loading/error state (20+ lines → 1 property) | 95% | API calls, data fetching |
| ExecuteAsync | Try-catch boilerplate (12 lines → 5 lines) | 58% | Error handling, async operations |
| UpdateThrottled | Throttle logic (22 lines → 1 line) | 95% | Mouse move, scroll events |
| LazyLoad | Cache + deduplication (15+ lines → 2 lines) | 85% | Expensive operations, API caching |
Quick Overview of Each Helper
UpdateDebounced - Debounced Search
Automatically debounces rapid state updates, perfect for search inputs and form validation.
<input @oninput="@(e => UpdateDebounced(s => s.SetQuery(e.Value?.ToString() ?? ""), 300))" />
AsyncData<T> - Simple Async State
Replaces 20+ lines of loading/data/error state management with a single property.
// State definition
public record UserState(AsyncData<User> User);
// Component usage
@if (State.User.IsLoading) { <p>Loading...</p> }
@if (State.User.HasData) { <p>@State.User.Data.Name</p> }
@if (State.User.HasError) { <p>@State.User.Error</p> }
ExecuteAsync - Automatic Error Handling
Eliminates try-catch boilerplate with automatic error handling and state transitions.
await ExecuteAsync(
() => Service.LoadAsync(),
loading: s => s with { Data = s.Data.ToLoading() },
success: (s, data) => s with { Data = AsyncData.Success(data) },
error: (s, ex) => s with { Data = AsyncData.Failure(ex.Message) }
);
UpdateThrottled - High-Frequency Events
Throttles rapid events to a maximum frequency, ideal for mouse move and scroll handlers.
// Throttle mouse move to max once per 100ms
<div @onmousemove="@(e => UpdateThrottled(s => s.SetPosition(e.ClientX, e.ClientY), 100))">
Mouse tracker
</div>
LazyLoad - Automatic Caching
Provides automatic caching with expiration and request deduplication for expensive operations.
// Automatic caching with 5-minute expiration + request deduplication
var user = await LazyLoad(
$"user-{userId}",
() => UserService.GetUserAsync(userId),
cacheFor: TimeSpan.FromMinutes(5));
// If 10 components call this simultaneously, only 1 API call is made!
Complete Example: Combining All Helpers
Here's a real-world example that demonstrates all five async helpers working together in a product search component:
@page "/products"
@inherits StoreComponent<ProductState>
<!-- 1. Debounced search -->
<input @oninput="@(e => UpdateDebounced(s => s.SetQuery(e.Value?.ToString() ?? ""), 300))"
placeholder="Search..." />
<!-- 2. Load with ExecuteAsync -->
<button @onclick="Search">Search</button>
<!-- 3. Display with AsyncData -->
@if (State.Products.IsLoading) { <p>Loading...</p> }
@if (State.Products.HasData)
{
@foreach (var product in State.Products.Data)
{
<div @onclick="@(() => LoadDetails(product.Id))">@product.Name</div>
}
}
@code {
async Task Search() =>
await ExecuteAsync(
() => ProductService.SearchAsync(State.Query),
loading: s => s with { Products = s.Products.ToLoading() },
success: (s, data) => s with { Products = AsyncData.Success(data) }
);
async Task LoadDetails(int id)
{
// 4. LazyLoad with caching
var details = await LazyLoad(
$"product-{id}",
() => ProductService.GetDetailsAsync(id),
TimeSpan.FromMinutes(5));
await Update(s => s.AddDetails(id, details));
}
}
Combine async helpers for maximum benefit. This example reduces approximately 100+ lines of boilerplate to just 30 lines of clean, readable code.
Key Benefits
74% Less Code
Eliminate repetitive patterns and focus on business logic instead of infrastructure.
More Readable
Intent is clear at a glance. No need to parse through timer management or error handling.
Battle-Tested
Production-ready with comprehensive test coverage and proven in real-world applications.
Zero Setup
Built into StoreComponent<T>. Just inherit and start using immediately.
Type-Safe
Full IntelliSense support and compile-time checking for all helpers.
Composable
Mix and match helpers as needed. They work seamlessly together.
Next Steps
Explore each helper in detail to learn about specific use cases, patterns, and best practices: