BlazorSignalStore 0.1.1

dotnet add package BlazorSignalStore --version 0.1.1
                    
NuGet\Install-Package BlazorSignalStore -Version 0.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BlazorSignalStore" Version="0.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BlazorSignalStore" Version="0.1.1" />
                    
Directory.Packages.props
<PackageReference Include="BlazorSignalStore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BlazorSignalStore --version 0.1.1
                    
#r "nuget: BlazorSignalStore, 0.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BlazorSignalStore@0.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BlazorSignalStore&version=0.1.1
                    
Install as a Cake Addin
#tool nuget:?package=BlazorSignalStore&version=0.1.1
                    
Install as a Cake Tool

BlazorSignalStore

NuGet Version NuGet Downloads GitHub License Build Status

A reactive state management library for Blazor applications inspired by Angular Signals

๐Ÿš€ Features

  • โœ… Angular Signals-inspired API - Familiar reactive patterns for Angular developers
  • โœ… React-like Hooks - useSignal() and function syntax support for React developers
  • โœ… Automatic UI Updates - Components re-render automatically when signals change
  • โœ… Computed Signals - Derived values that update when dependencies change
  • โœ… Type Safe - Full TypeScript-like experience with nullable reference types
  • โœ… Dependency Injection - Native .NET DI integration
  • โœ… Blazor Server & WebAssembly - Works with both hosting models
  • โœ… .NET 8+ Ready - Built for modern .NET applications

๐Ÿ“ฆ Installation

dotnet add package BlazorSignalStore

๐Ÿ”ง Quick Start

1. Register Services

// Program.cs
builder.Services.AddSignalStore<CounterStore>();

2. Create a Store

using BlazorSignalStore.Core;

public class CounterStore : StoreBase
{
    public Signal<int> Count { get; } = new(0);
    public Computed<string> Label { get; }
    
    public CounterStore()
    {
        Label = new Computed<string>(() => $"Count: {Count.Value}", Count);
    }
    
    public void Increment() => Count.Value++;
    public void Decrement() => Count.Value--;
}

3. Use in Components

@using BlazorSignalStore.Core
@inject CounterStore Store

<h3>@label()</h3>
<button @onclick="Store.Increment">+</button>
<button @onclick="Store.Decrement">-</button>

@code {
    private Func<int>? count;
    private Func<string>? label;
    
    protected override void OnInitialized()
    {
        count = this.useSignal(Store.Count);
        label = this.useSignal(Store.Label);
    }
}

๐Ÿ’ก Core Concepts

Signals

Reactive containers that notify subscribers when their value changes:

// Create a signal
var signal = new Signal<string>("initial value");

// Subscribe to changes
var subscription = signal.Subscribe(newValue => 
    Console.WriteLine($"Value changed to: {newValue}"));

// Update value (triggers subscribers)
signal.Value = "new value";

// Clean up
subscription.Dispose();

Computed Signals

Derived values that automatically recalculate when dependencies change:

var firstName = new Signal<string>("John");
var lastName = new Signal<string>("Doe");

var fullName = new Computed<string>(() => $"{firstName.Value} {lastName.Value}");

Console.WriteLine(fullName.Value); // "John Doe"

firstName.Value = "Jane"; 
Console.WriteLine(fullName.Value); // "Jane Doe" (automatically updated)

Blazor Integration

Use the useSignal extension method for automatic component re-rendering:

@using BlazorSignalStore.Core
@inject MyStore Store

@code {
    private Func<bool>? isLoading;
    
    protected override void OnInitialized()
    {
        isLoading = this.useSignal(Store.IsLoading);
        
        // Component automatically re-renders when isLoading changes
    }
}

๐Ÿ“‹ API Reference

Signal<T>

  • Value - Get/set the current value
  • Subscribe(Action<T>) - Subscribe to value changes
  • Implicit conversion to Func<T> for React-like syntax

Computed<T>

  • Value - Get the computed value (readonly)
  • Subscribe(Action<T>) - Subscribe to computed value changes
  • Constructor takes computation function and dependency signals

SignalHooks Extensions

  • useSignal<T>(Signal<T>) - Create a function that triggers component re-renders
  • useSignal<T>(Computed<T>) - Subscribe to computed signals in components
  • Integrates with Blazor component lifecycle

StoreBase

  • Base class for creating organized signal stores
  • Inherit from this class to group related signals and computed values

๐ŸŽฏ Patterns

Store-based Architecture

public class CounterStore : StoreBase
{
    public Signal<int> Count { get; } = new(0);
    public Computed<string> DisplayText { get; }
    
    public CounterStore()
    {
        DisplayText = new Computed<string>(() => $"Count: {Count.Value}", Count);
    }
}

// In component
@inject CounterStore Store

<p>@displayText()</p>

@code {
    private Func<string>? displayText;
    
    protected override void OnInitialized()
    {
        displayText = this.useSignal(Store.DisplayText);
    }
}

Computed Dependencies

public class ItemStore : StoreBase
{
    public Signal<List<Item>> Items { get; } = new(new());
    public Computed<int> ItemCount { get; }
    public Computed<bool> HasItems { get; }
    
    public ItemStore()
    {
        ItemCount = new Computed<int>(() => Items.Value.Count, Items);
        HasItems = new Computed<bool>(() => ItemCount.Value > 0, ItemCount);
    }
}

Complex State Management

public class AppStore : StoreBase
{
    public Signal<User?> CurrentUser { get; } = new(null);
    public Signal<bool> IsLoading { get; } = new(false);
    public Computed<bool> IsAuthenticated { get; }
    
    public AppStore()
    {
        IsAuthenticated = new Computed<bool>(() => CurrentUser.Value != null, CurrentUser);
    }
}

๐Ÿ—๏ธ Architecture

BlazorSignalStore is built with:

  • Signal<T> - Core reactive primitive with subscription management
  • Computed<T> - Derived state with explicit dependency tracking
  • useSignal Extensions - Blazor component integration methods
  • StoreBase - Base class for organizing related signals
  • Reflection-based updates - Automatic StateHasChanged() calls via useSignal
  • Dependency Injection - Native .NET DI integration via AddSignalStore<T>()

๐Ÿงช Testing

The library includes comprehensive tests covering:

  • Core signal functionality (11 tests) โœ…
  • Dependency injection integration (5 tests) โœ…
  • Computed signal behavior
  • Blazor component integration
  • Memory leak prevention
  • Thread safety

Run tests:

dotnet test

๐Ÿ“š Documentation

๐Ÿค Contributing

Contributions are welcome! Please read our contribution guidelines.

๐Ÿ“„ License

This project is licensed under the MIT License. See LICENSE for more details.

๐Ÿ™ Acknowledgments

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.1 279 10/19/2025
0.1.0 172 10/17/2025

v0.1.1: Fixed security vulnerabilities, improved CI/CD pipeline, and ensured cross-platform compatibility with consistent line endings.