Core Concepts

Understanding the fundamental principles of EasyAppDev.Blazor.Store will help you build better Blazor applications with simple, type-safe state management.

State = Immutable Record

State in EasyAppDev.Blazor.Store is defined as immutable C# records with transformation methods. This pattern ensures predictability, testability, and type safety.

TodoState.cs
public record TodoState(ImmutableList<Todo> Todos)
{
    public static TodoState Initial => new(ImmutableList<Todo>.Empty);

    public TodoState AddTodo(string text) =>
        this with { Todos = Todos.Add(new Todo(Guid.NewGuid(), text, false)) };

    public TodoState ToggleTodo(Guid id) =>
        this with {
            Todos = Todos.Select(t =>
                t.Id == id ? t with { Completed = !t.Completed } : t
            ).ToImmutableList()
        };
}
Key Principles
  • Pure functions - State methods have no side effects and no I/O operations
  • Always use with expressions - Never mutate state directly
  • Use ImmutableList<T> - For collections that need to be modified
  • Co-locate transformation logic - Keep state methods with state data

StoreComponent = Automatic Reactivity

By inheriting from StoreComponent<TState>, your components get automatic subscription to state changes and reactive updates without any manual wiring.

๐Ÿ”Œ

Automatic Subscription

Components automatically subscribe to state changes on initialization

๐Ÿ“ก

State Property

Access current state directly via the State property

๐Ÿ”„

Update Method

Call Update() to apply state transformations

๐Ÿงน

Automatic Cleanup

Subscriptions are disposed when component is destroyed

TodoList.razor
@inherits StoreComponent<TodoState>

<button @onclick="AddTodo">Add</button>

@code {
    async Task AddTodo() => await Update(s => s.AddTodo("New task"));
}

Update Flow

Understanding how state updates flow through the system helps you reason about your application's behavior.

1

Component calls Update()

Your component calls Update(s => s.Method()) with a transformation function

await Update(s => s.Increment())
โ†“
2

Store applies transformation

The store acquires a lock and applies your transformation function to the current state

โ†“
3

New state created

A new immutable state object is created. The old state remains unchanged

This ensures you can always safely compare or rollback states!

โ†“
4

All subscribers notified

Every component subscribed to this store receives the new state

โ†“
5

Components re-render

Each subscribed component automatically triggers StateHasChanged() and re-renders with the new state

Key Principles Summary

โœ… Do

  • Use C# records for all state
  • Use with expressions for updates
  • Keep state methods pure (no side effects)
  • Use ImmutableList<T> and ImmutableDictionary<K,V>
  • Inherit from StoreComponent<T> for automatic reactivity
  • Call Update() with transformation functions

โŒ Don't

  • Mutate state properties directly
  • Use mutable collections like List<T>
  • Add side effects to state methods
  • Call APIs or log from state methods
  • Forget to use await with Update()
  • Manually subscribe/unsubscribe from stores

Next Steps