If you’ve done much with the likes of React you’ll probably know about the Flux pattern and implementations thereof, such as Redux and the Redux Toolkit (RTK). Well, There’s an implementation of the pattern for Blazor named Fluxor, let’s take a look at using this in our Blazor application.
Note: I’m using .NET 9 for this sample project.
I’m going to be leaning heavily on the Fluxor Tutorials to get started, so I’d definitely recommend checking them out.
- Create yourself a Blazor application or use an existing one, I’m using a Blazor Standalone application for this post.
- Add the NuGet packages
- Fluxor
- Fluxor.Blazor.Web
- Fluxor.Blazor.Web.ReduxDevTools
-
In Program.cs add the line
builder.Services.AddFluxor(options => options.ScanAssemblies(typeof(Program).Assembly));
- Add the following to the start of the App.razor file
<Fluxor.Blazor.Web.StoreInitializer/>
This initializes the store.
At this point we have the basics in place to use Fluxor, but now let’s see the store in work.
We’re going to start by implementing state for the sample Counter page. Again, please refer to the Fluxor Tutorials that cover this in more detail than I’m going to.
The Flux pattern
The In Depth Overview is a useful starting point as is The Fluxor Documentation to understand the Flux pattern.
Before we get into the code, let’s just review our understanding and expectations of Fluxor and the Flux pattern in general.
One important things to remember is function/methods such as the reducers should be pure functions. Data should therefore be immutable in that the data you send into the store and this any returned data will be a copy with any changes made on the copy.
Using the Blazor sample Counter page we have this workflow
- Page intializes, we display an initial count
- When the user clicks the button, we Dispatch an action via the Dispatcher
reducer which then gets stored within the state. - The state updates so that anything watching it can update, hence the state updates and the UI then updates
Some code
Let’s be a little boring and use the Counter.razor sample code.
First off we’re create our CounterState.cs file
[FeatureState] public class CounterState { public int ClickCount { get; } private CounterState() { } public CounterState(int clickCount) { ClickCount = clickCount; } }
We need a default ctor for initialization if the state, but this can be private. The other constructor will be used to create a new copy of the counter state.
I’m going to stick to just using the .razor file, so within Counter.razor I’ve added
@inject IState<CounterState> CounterState @inject IDispatcher Dispatcher
Now we can simply using the following to get the current state
@CounterState.Value.ClickCount
When we click a button we’ll dispatch an action IncrementCounterAction like this
private void IncrementCount() { Dispatcher.Dispatch(new IncrementCounterAction()); }
Where IncrementCounterAction is simply as follows
public class IncrementCounterAction;
Finally we need a reducer which accepts this action and this creates a copy of our updated data like this
public static class Reducers { [ReducerMethod(typeof(IncrementCounterAction))] public static CounterState ReduceIncrementCounterAction(CounterState state) => new CounterState(clickCount: state.ClickCount + 1); }
We can write a reducer in a couple of other ways, for example
public static class Reducers { [ReducerMethod] public static CounterState ReduceIncrementCounterAction(CounterState state, IncrementCounterAction action) => new CounterState(clickCount: state.ClickCount + 1); }
Or as follows
public class IncrementCounterReducer : Reducer<CounterState, IncrementCounterAction> { public override CounterState Reduce(CounterState state, IncrementCounterAction action) => new CounterState(clickCount: state.ClickCount + 1); }