Course contentsShow
← C#
Lesson 1347 of 1,90812. Modern Frontend with Razor and BlazorFree lesson

Flux and Redux Patterns in Blazor

Implement a robust state management pattern to handle complex UI state transitions.

In this lesson, you will learn how to implement the Flux and Redux patterns in Blazor to centralize your application state and create predictable UI transitions.

Understanding the Pattern

In a standard Blazor app, components often hold their own state, leading to "spaghetti" data flows as your app grows. The Redux pattern solves this by enforcing a unidirectional data flow through three core pillars:

  1. State: A single, immutable object representing the entire application's data.
  2. Actions: Simple commands that describe what happened (e.g., IncrementCounterAction).
  3. Reducers: Pure functions that take the current state and an action, then return a new state.

Implementation Strategy

In Blazor, we leverage the Dependency Injection (DI) Container (Concept 13) to hold a singleton Store. Components inject this store and subscribe to state changes.

Consider a simple counter state:

// The State
public record CounterState(int Count);

// The Store
public class CounterStore
{
    private CounterState _state = new(0);
    public CounterState State => _state;
    public event Action? OnChanged;

    public void Dispatch(string action)
    {
        if (action == "INCREMENT")
            _state = _state with { Count = _state.Count + 1 };
        
        OnChanged?.Invoke(); // Notify UI to re-render
    }
}

Integrating with Blazor Components

Because the state is held in a centralized CounterStore, multiple components can observe the same data. By subscribing to the OnChanged event in OnInitialized, you ensure your component refreshes whenever the state updates:

@implements IDisposable
@inject CounterStore Store

<p>Count: @Store.State.Count</p>
<button @onclick='() => Store.Dispatch("INCREMENT")'>Add</button>

@code {
    protected override void OnInitialized() => Store.OnChanged += StateHasChanged;
    public void Dispose() => Store.OnChanged -= StateHasChanged;
}

By decoupling the logic (the Store) from the UI (the Component), you ensure that state transitions are testable and debuggable. Since the state is immutable (using record and with), you prevent side-effect bugs where components inadvertently mutate shared data.

Key Takeaway: The Flux pattern centralizes state into a single source of truth, forcing all UI changes to flow through explicit actions and pure reducers, resulting in a predictable and easily scalable Blazor architecture.