NetRx.Store
1.4.1
See the version list below for details.
dotnet add package NetRx.Store --version 1.4.1
NuGet\Install-Package NetRx.Store -Version 1.4.1
<PackageReference Include="NetRx.Store" Version="1.4.1" />
paket add NetRx.Store --version 1.4.1
#r "nuget: NetRx.Store, 1.4.1"
// Install NetRx.Store as a Cake Addin #addin nuget:?package=NetRx.Store&version=1.4.1 // Install NetRx.Store as a Cake Tool #tool nuget:?package=NetRx.Store&version=1.4.1
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:
- 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;
}
- 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 | Versions 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. |
-
.NETStandard 2.0
- Microsoft.CSharp (>= 4.5.0)
- System.Collections.Immutable (>= 1.5.0)
- System.Reactive (>= 4.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.