Blazor Web Assembly test project with Fluxor.
Fluxor + C#9 - Redux Pattern in Blazor WebAssembly.
- Install the Fluxor.Blazor.Web NuGet package.
- Optional: Instal the Fluxor.Blazor.Web.ReduxDevTools NuGet package. This package is necessary only if Redux Dev Tools will be used.
- Add the following line to index.html:
<body>
...
<script src="_content/Fluxor.Blazor.Web/scripts/index.js"></script>
</body>
- Add <Fluxor.Blazor.Web.StoreInitializer /> to App.razor:
<Fluxor.Blazor.Web.StoreInitializer />
...
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
...
</Router>
<Fluxor.Blazor.Web.StoreInitializer /> initialises the store automatically.
- Add the following code to Main in Program.cs:
...
using Fluxor;
...
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
...
builder.Services.AddFluxor(options => options
.ScanAssemblies(typeof(Program).Assembly)
.UseReduxDevTools() // Optional. Needed if Redux Dev Tools will be used. Requires the Fluxor.Blazor.Web.ReduxDevTools NuGet package.
.UseRouting()
);
...
await builder.Build().RunAsync();
}
- Create a folder named Store. For every component that needs to manage and/or share state, create a subfolder under the Store folder with its name and create the following classes inside (note: for state and action, a record can be used):
- State;
- Feature (this class describes the state to the store);
- Action;
- Reducers.
Example:
- CounterState:
namespace BlazorWebAssemblyFluxor.Store.Counter
{
public record CounterState
{
public int ClickCount { get; init; }
}
}
- CounterFeature:
using Fluxor;
namespace BlazorWebAssemblyFluxor.Store.Counter
{
public class CounterFeature : Feature<CounterState>
{
public override string GetName() => nameof(CounterState);
protected override CounterState GetInitialState() => new() { ClickCount = 0 };
}
}
- CounterActionIncrement:
namespace BlazorWebAssemblyFluxor.Store.Counter
{
public record CounterActionIncrement { }
}
- CounterReducers (don't forget to decorate methods with [ReducerMethod]):
using Fluxor;
namespace BlazorWebAssemblyFluxor.Store.Counter
{
public class CounterReducers
{
[ReducerMethod]
public static CounterState ReduceCounterActionIncrement(CounterState state, CounterActionIncrement action)
{
return state with
{
ClickCount = state.ClickCount + 1
};
}
[ReducerMethod]
public static CounterState ReduceCounterActionReset(CounterState state, CounterActionReset action) => new() { ClickCount = 0 };
}
}
- Add Fluxor to every component that needs to manage and/or share state. Example:
@page "/counter"
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@using Fluxor
@using BlazorWebAssemblyFluxor.Store.Counter
@inject IState<CounterState> CounterState
@inject IDispatcher Dispatcher
<h1>Counter</h1>
<p>Current count: @CounterState.Value.ClickCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
var action = new IncrementCounterAction();
Dispatcher.Dispatch(action);
}
}
NOTES:
The components must:
- Use Fluxor:
@using Fluxor
- Inherit from Fluxor.Blazor.Web.Components.FluxorComponent:
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
- Use the store part(s) they need. Example:
@using BlazorWebAssemblyFluxor.Store.Counter
- Inject IDispatcher:
@inject IDispatcher Dispatcher