NetRx.Store 1.4.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package NetRx.Store --version 1.4.0                
NuGet\Install-Package NetRx.Store -Version 1.4.0                
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="NetRx.Store" Version="1.4.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add NetRx.Store --version 1.4.0                
#r "nuget: NetRx.Store, 1.4.0"                
#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.
// Install NetRx.Store as a Cake Addin
#addin nuget:?package=NetRx.Store&version=1.4.0

// Install NetRx.Store as a Cake Tool
#tool nuget:?package=NetRx.Store&version=1.4.0                

Core concepts

Core principles are the same as in @ngrx/store:

  • State is a single immutable data structure
  • Actions represent state changes
  • Reducers take the previous state and the next action to compute the new state
  • Effects allows to express side effects through actions (typically asynchronous operations, like reading data from file, sending HTTP-request, etc.)
  • Store holds states, their reducers and effects. It plays the role of single source of truth

Overview

State

State cannot have reference type, it should be struct and can have properties of following types: simple type (bool, int, double, string, etc), collection type from System.Collections.Immutable namespace or user defined struct.

Example:

public struct AppState
{
    public bool IsLoading { get; set; }
    public string Status { get; set; }
    public decimal Amount { get; set; }
    public UserInfo User { get; set; }
    public ImmutableList<Person> Contacts { get; set; }
}
Action

User defined actions should be inherited from Action class defined in NetRx.Store namespace.

Example:

public class RefreshStatus : NetRx.Store.Action
{
}

public class SetIsLoading : NetRx.Store.Action<bool>
{
    public SetIsLoading(bool payload) : base(payload)
    {
    }
}
Reducer

There are two options how you can define reducers for your states:

  1. You can use a pure function with the following syntax: Func<ProfileState, Action, ProfileState>.

Example:

Func<ProfileState, Action, ProfileState> reducer = (state, action) =>
{
    if (action is actions.SetEmail setEmail)
    {
        state.Email = setEmail.Payload;
        return state;
    }
    if (action is actions.SetName setName)
    {
        state.Name = setName.Payload;
        return state;
    }
    if (action is actions.AddContact addContact)
    {
        state.Contacts = state.Contacts.Add(addContact.Payload);
        return state;
    }
    if (action is actions.ClearContacts)
    {
        state.Contacts = state.Contacts.Clear();
        return state;
    }

    return state;
}
  1. You can define reducer as a class (then it needs to be inherited from NetRx.Store.Reducer<TState>). Reducer class should have a set of methods with the following syntax:

public TSate Reduce(TState state, TAction action)

Example:

public class AppReducer : Reducer<AppState>
{
    public ProfileState Reduce(ProfileState state, SetIsLoading action)
    {
        state.IsLoading = action.Payload;
        return state;
    }

    public ProfileState Reduce(ProfileState state, SetUserName action)
    {
        state.User.Name = action.Payload;
        return state;
    }

    public ProfileState Reduce(ProfileState state, AddContact action)
    {
        state.Contacts = state.Contacts.Add(action.Payload);
        return state;
    }

    public ProfileState Reduce(ProfileState state, ClearContacts action)
    {
        state.Contacts = state.Contacts.Clear();
        return state;
    }
}
Effects

User defined effects should be inherited from Effect class defined in NetRx.Effects namespace.

Example:

public class UsernameChangedEffect : Effect<SetUsername>
{
    public override async Task Invoke(SetUsername action)
    {
        await NotificationService.NotifyUserNameChange(action.Payload);
    }
}

public class LoadDataEffect : Effect<LoadData, LoadDataSuccess>
{
    public override async Task<LoadDataSuccess> Invoke(LoadData action)
    {
        var result = await DataService.Load();
        return new LoadDataSuccess(new Data
        {
            Count = result.Count,
            Category = result.Category,
            Timestamp = DateTime.UtcNow
        });
    }
}
Store

Store can be created by calling static method Store.Create(). It returns the instance of BlankStore - store that doesn't have any states, reducers or effects. To put some state and reducer into it you have to call WithState method and pass the initial state and the reducer to it.

Example:

using NetRx.Store

...

var initialAppState = new AppState
{
    IsLoading = false,
    Status = "none" 
};

var store = Store.Create()
     .WithState(initialAppState, new AppReducer())
     .WithState(new ContactState(), new ContactReducer())
     .WithState(new ProductState(), new ProductReducer());

As you can see from the example above, you can call WithState method few times one by one and you will get the store that contains all of the passed states with their reducers. After that you can subscribe to listen to the state properties changes:

store.Select<AppState, string>(state => state.Status)
     .Subscribe(value =>
     {
	     Console.WriteLine(value);
     })

To trigger state changes you can call Dispatch method on the store:

store.Dispatch(new SetIsLoading(true));
store.Dispatch(new RefreshStatus());

To register some effects in your store, you can call WithEffects method right after adding states and reducers to it:

Store.Create()
     .WithState(initialAppState, new AppReducer())
     .WithEffects(new Effect[] { new LoadDataEffect(), new UsernameChangedEffect() });

In this case passed effects will be invoked when the corresponding action will be dispatched in the store.

Examples

You can find sample projects here

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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
2.0.0 1,404 8/27/2019
1.4.1 1,348 2/20/2019
1.4.0 1,398 10/14/2018
1.3.1 1,460 10/10/2018
1.3.0 1,454 10/7/2018
1.2.1 1,424 10/4/2018
1.2.0 1,410 10/3/2018
1.1.0 1,399 10/1/2018
1.0.0 1,428 9/30/2018