Blex for Blazor

Getting started

Quick start

A complete, reactive, time-travelable counter in three files and about twenty lines.

1. Write the store

A store is a partial class marked [BlexStore]. Fields marked [BlexState] become reactive properties; methods marked [BlexAction] become public wrappers that record a single named action.

C#
Stores/CounterStore.cs
using Bit.Blex;

namespace MyApp.Stores;

[BlexStore(Name = "counter")]
public partial class CounterStore
{
    [BlexState] private int _count;
    [BlexState] private int _step = 1;

    [BlexComputed] private int  ComputeDoubleCount() => Count * 2;
    [BlexComputed] private bool ComputeIsEven()      => Count % 2 == 0;

    [BlexAction] private void OnIncrement() => Count += Step;
    [BlexAction] private void OnDecrement() => Count -= Step;
}

The naming conventions are mechanical, and the generator enforces them:

You writeYou getRule
[BlexState] private int _count;public int Count { get; set; }Strip a leading underscore, capitalize.
[BlexComputed] int ComputeDoubleCount()public int DoubleCount { get; }Strip Compute or Get.
[BlexAction] void OnIncrement()public void Increment()Strip the On prefix.
[BlexEffect] async Task OnLoad()public Task Load() + LoadIsLoading + LoadErrorStrip On, add the lifecycle.

2. Register it

C#
Program.cs
builder.Services.AddBitBlexServices();
builder.Services.AddBitBlexStore<CounterStore>();

3. Wrap the app and use the store

Razor
App.razor
<BlexProvider>
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound><p>Not found.</p></NotFound>
    </Router>
</BlexProvider>
Razor
Pages/Counter.razor
@page "/counter"
@inherits BlexComponentBase
@inject CounterStore Counter

<p>Count: @Counter.Count (double: @Counter.DoubleCount)</p>

<button class="btn" @onclick="Counter.Increment">Increment</button>
<button class="btn" @onclick="Counter.Decrement">Decrement</button>

@code {
    protected override void OnInitialized() => Subscribe(Counter);
}

BlexComponentBase.Subscribe(store) re-renders the component whenever that store changes, and detaches automatically when the component is disposed. That is the whole integration - there is no StateHasChanged to call and nothing to unsubscribe.

Live demo The finished counter

Exactly the code above. Every click is a named action: watch the Inspector at the bottom of the page.

Count 0
DoubleCount 0
IsEven True

What you got for free

Batched renders

Every mutation inside an action is folded into one notification, so a five-field action re-renders the component once - not five times.

Named, inspectable actions

Each action carries its name and its argument payload to middleware, subscribers and the DevTools extension.

Snapshots

SerializeState() / DeserializeState() are generated, which is what makes persistence, undo/redo and time-travel possible.

Compile-time safety

Sixteen diagnostics catch a malformed store at build time rather than emitting code that does not compile. See Diagnostics.

Where to next

An unhandled error has occurred. Reload ๐Ÿ—™