Table of Contents

Getting Standard

In this tutorial, you will learn how to update the actual UI in Blazor !

Install Memento.Blazor in the Blazor component to update the Store state.

Memento.Blazor contains components that allow UI components to know about state updates and automatically update the UI. Memento.Core is included in the dependencies and does not need to be installed additionally. Memento.Core is a core library consisting of pure .NET code only. NET class library or for console apps that do not use a UI framework such as Blazor, install Memento.Core.

Depends on Microsoft.AspNetCore.Components. It can also be used with native UI frameworks such as MobileBlazorBindings and BlazorBindings.Maui because it does not depend on Microsoft.AspNetCore.Components.Web.

Blazor

https://docs.microsoft.com/ja-jp/aspnet/core/blazor/ https://dotnet.microsoft.com/ja-jp/apps/aspnet/web-apps/blazor

MobileBlazorBindings

https://github.com/dotnet/MobileBlazorBindings

BlazorBindings.Maui

https://github.com/Dreamescaper/BlazorBindings.Maui

Install

Install Memento.Blazor for the Blazor projects. Install Memento.Core for the pure NET project that do not use the UI framework like .NET Class library or Console App.

Install with CLI

Memento.Blazor

dotnet add package Memento.Blazor

Memento.Core

dotnet add package Memento.Core

Install from Nuget

Memento.Blazor Nuget

https://www.nuget.org/packages/Memento.Blazor

Memento.Core Nuget

https://www.nuget.org/packages/Memento.Core

Initialization

Blazor uses Dependency Injection in the framework.

Here is how to use Memento in your application.

Registers all required modules with AddMemento() . Registers all the stores present in the specified assembly with ScanAssemblyAndAddStores() . Specifically, all classes that inherit from ````IStore``` will be registered.

registers an individual Store specified by AddStore<TStore>() . Register the required services in Program.cs etc. Add middleware with ```AddMiddleware(...)`` . Add middleware if necessary.

If isScoped: false, it will be registered as a Singleton, if isScoped: true, it will be registered as a Scoped service. In the case of Blazor Server, the state is separated for each user session, so the argument isScoped: true must be set or the state will be shared by all users. The default args is isScoped: true.

using Memento.Blazor;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services
    // Add necessary modules to Memento
    .AddMemento(isScoped: false)
     // Add middleware
    .AddMiddleware<LoggerMiddleware>(isScoped: false)
     // Add by specifying Store
    .AddStore<AsyncCounterStore>(isScoped: false)
    // Scan the assembly and register all classes that implement the IStore interface
    .ScanAssemblyAndAddStores(typeof(Program).Assembly, isScoped: false);

await builder.Build().RunAsync();

Next, MementoInitializer to the component root, such as App.razor. This will initialize the necessary Memento modules.

<MementoInitializer />

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

Component usage

Using @inject in Store will be automatically resolved by the DI container. By inheriting from ObserverComponent. Injected Stores that extend Store<TState> or FluxStore<TState, TCommand> are automatically observed by reflection. This allows the View to automatically update the state of the Store automatically

This is an example of Counter.


@using Memento.Sample.Blazor.Stores
@using System.Text.Json

@page "/counter"
@inherits ObserverComponent
@inject AsyncCounterStore AsyncCounterStore

<PageTitle>Counter</PageTitle>

<div>
    <h1 class="mt-5">Async Counter</h1>
    <h2>Current count: @AsyncCounterStore.State.Count</h2>
    <p>Loading: @AsyncCounterStore.State.IsLoading</p>

    <div>
        <button class="mt-3 btn btn-primary" @onclick="IncrementCount">Count up</button>
        <button class="mt-3 btn btn-primary" @onclick="CountupMany">Count up 100 times</button>
    </div>

    <div class="mt-5">
        <h3>Count up async with histories</h3>
        <button class="mt-3 btn btn-primary" @onclick="IncrementCountAsync">Count up async</button>
        <p class="mt-3 mb-0">Histories</p>
        <div class="d-flex">
            @foreach (var item in string.Join(", ", AsyncCounterStore.State.Histories)) {
                @item
            }
        </div>
    </div>

    <div class="mt-5">
        <h3>Count up with Amount</h3>
        <input @bind-value="_amount" />
    </div>
    <button class="mt-3 btn btn-primary" @onclick="CountupWithAmount">Count up with amount</button>

    <div class="mt-5">
        <h3>Set count</h3>
        <input @bind-value="_countToSet" />
    </div>
    <button class="mt-3 btn btn-primary" @onclick="SetCount">Count up with amount</button>
</div>

@code {
    int _amount = 5;
    int _countToSet = 100;

    void IncrementCount() {
        AsyncCounterStore.CountUp();
    }

    async Task IncrementCountAsync() {
        await AsyncCounterStore.CountUpAsync();
    }

    void CountupMany() {
        AsyncCounterStore.CountUpManyTimes(100);
    }

    void CountupWithAmount() {
        AsyncCounterStore.CountUpWithAmount(_amount);
    }

    void SetCount() {
        AsyncCounterStore.SetCount(_countToSet);
    }
}

Another way to use

If inherit cannot be used due to conflicts with other libraries, please use StateChangedObserver. If you specify IObservable for Observables, it will automatically track state changes and notify OnStateHasChanged.

<StateChangedObserver Observables="[Store1, Store2, Store3]" OnStateHasChanged="StateHasChanged" />

sample


@page "/counter"
@inject AsyncCounterStore AsyncCounterStore

<PageTitle>Counter</PageTitle>

<StateChangedObserver Observables="[AsyncCounterStore]" OnStateHasChanged="StateHasChanged" />

<div>
    <h1 class="mt-5">Async Counter</h1>
    <h2>Current count: @AsyncCounterStore.State.Count</h2>
    <p>Loading: @AsyncCounterStore.State.IsLoading</p>
</div>