MentorLake.Redux
1.2.4
dotnet add package MentorLake.Redux --version 1.2.4
NuGet\Install-Package MentorLake.Redux -Version 1.2.4
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="MentorLake.Redux" Version="1.2.4" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MentorLake.Redux" Version="1.2.4" />
<PackageReference Include="MentorLake.Redux" />
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 MentorLake.Redux --version 1.2.4
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: MentorLake.Redux, 1.2.4"
#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 MentorLake.Redux@1.2.4
#: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=MentorLake.Redux&version=1.2.4
#tool nuget:?package=MentorLake.Redux&version=1.2.4
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Getting Started
Create state types
public record PersonState(string FirstName, string LastName);
public record AddressState(string ZipCode);
Create action types
public record UpdateFirstNameAction(string FirstName);
public record UpdateLastNameAction(string LastName);
public record ZipCodeUpdatedAction(string ZipCode);
Create reducers
public class MyReducers : IReducerFactory
{
public FeatureReducerCollection Create() =>
[
FeatureReducer.Build(new PersonState("Hello", "World"))
.On<UpdateFirstNameAction>((state, action) => state with { FirstName = action.FirstName })
.On<UpdateLastNameAction>((state, action) => state with { LastName = action.LastName }),
FeatureReducer.Build(new AddressState("12345"))
.On<ZipCodeUpdatedAction>((state, action) => state with { ZipCode = action.ZipCode })
];
}
Create and setup redux store
var serviceProvider = new ServiceCollection()
.AddTransient<IReducerFactory, MyReducers>()
.BuildServiceProvider();
var store = new ReduxStore();
store.RegisterReducers(serviceProvider.GetServices<IReducerFactory>().ToArray());
Dispatch an action
await store.Dispatch(new UpdateFirstNameAction("Bob"));
The Dispatch method returns a task that completes after the reducers and effects run. Note, the task does not wait for asynchronous effects to complete.
Selectors
Creating selectors
public class MySelectors
{
public static readonly ISelector<PersonState> Person = SelectorFactory.CreateFeature<PersonState>();
public static readonly ISelector<string> FirstName = SelectorFactory.Create(Person, s => s.FirstName);
public static readonly ISelector<AddressState> Address = SelectorFactory.CreateFeature<AddressState>();
public static readonly ISelector<string> ZipCode = SelectorFactory.Create(Address, s => s.ZipCode);
}
Using a selector
store.Select(MySelectors.FirstName).Subscribe(firstName => Console.WriteLine(firstName));
Custom comparison function
private bool CompareFirstNamesOnly(PersonState x, PersonState y)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
return x.FirstName.Equals(y.FirstName);
}
var personSelector = SelectorFactory.Create(MySelectors.Person, p => p, CompareFirstNamesOnly);
// or
var personSelector = SelectorFactory.Create(MySelectors.Person.WithComparer(CompareFirstNamesOnly), p => p);
Effects
Defining
public class MyEffects(PersonService personService) : IEffectsFactory
{
public IEnumerable<Effect> Create() => new[]
{
// Vanilla effect with no dispatch
EffectsFactory.Create(actions => actions
.OfType<SavePersonAction>()
.Do(action => personService.SavePerson(action.Person))),
// Async effect with actions dispatched
EffectsFactory.Create(actions => actions
.OfType<SavePersonAction>()
.Select(action => Observable.FromAsync(() => personService.SavePersonAsync(action.Person)))
.Concat()
.SelectMany(_ => new object[] { new SavePersonCompleteAction(), new SomeOtherAction() }),
new EffectConfig() { Dispatch = true })
};
}
Registration
var serviceProvider = new ServiceCollection()
.AddTransient<IEffectsFactory, MyEffects>()
.AddTransient<PersonService>()
.BuildServiceProvider();
var store = new ReduxStore();
store.RegisterEffects(serviceProvider.GetServices<IEffectsFactory>().ToArray());
Thunks
Defining
public static class MyThunks
{
public static ThunkAction NoArgNoReturnThunk = new(
"NoArgNoReturnThunk",
async api => await Task.Delay(1000));
public static ThunkAction<int> ThunkWithArgs = new(
"ThunkWithArgs",
async (api, i) => await Task.Delay(i));
public static ThunkFunc<string> ThunkWithReturnValue = new(
"ThunkWithReturnValue",
(api) => Task.FromResult("Hello World"));
public static ThunkFunc<int, string> ThunkWithArgAndReturnValue = new(
"ThunkWithArgAndReturnValue",
async (api, i) => Task.FromResult(i.ToString()));
public static ThunkAction ThunkUsingSelector = new(
"ThunkUsingSelector",
api =>
{
var firstName = FirstNameSelector.Apply(api.State);
Console.WriteLine(firstName);
return Task.CompletedTask;
});
public static ThunkAction ThunkDispatchingActions = new(
"ThunkDispatchingActions",
api =>
{
api.Dispatch(new MyAction());
return Task.CompletedTask;
});
}
If you need dependency injection then declare your thunks as non-static in a non-static class.
Usage
// Pending Action
store.DispatchThunk(MyThunks.NoArgNoReturnThunk.Bind()).Actions
.Action<ThunkPending>("NoArgNoReturnThunk/pending")
.Subscribe(action =>
{
Console.WriteLine("Thunk started.");
});
// Fulfilled action
store.DispatchThunk(MyThunks.ThunkWithArgAndReturnValue.Bind(123)).Actions
.Action<ThunkFulfilled<string>>("ThunkWithArgs/fulfilled")
.Subscribe(action =>
{
Console.WriteLine($"Returned value: {action.Result}");
});
// Custom action
store.DispatchThunk(MyThunks.ThunkWithArgAndReturnValue.Bind(123)).Actions
.OfType<MyAction>()
.Subscribe(action =>
{
Console.WriteLine($"My action received!");
});
// Task
var result = await store.DispatchThunk(MyThunks.ThunkWithArgAndReturnValue.Bind(123)).ToTask();
Console.WriteLine($"Returned value: {result}");
Thunk Reducer
public record MyThunkState(int CallCount);
public class MyThunkReducers : IReducerFactory
{
public FeatureReducerCollection Create() =>
[
FeatureReducer.Build(new MyThunkState(0))
.On<ThunkFinalized>("NoArgNoReturnThunk/fulfilled", (state, action) => state with { CallCount = state.CallCount + 1 })
];
}
| Product | Versions 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.
-
net8.0
- System.Reactive (>= 6.0.0)
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 |
|---|---|---|
| 1.2.4 | 185 | 11/28/2025 |
| 1.2.3 | 163 | 11/28/2025 |
| 1.2.2 | 163 | 11/23/2025 |
| 1.2.1 | 228 | 11/22/2025 |
| 1.1.5 | 174 | 7/5/2025 |
| 1.1.4 | 104 | 7/4/2025 |
| 1.1.2 | 246 | 1/26/2024 |
| 1.1.1 | 162 | 1/25/2024 |
| 1.0.8 | 172 | 1/22/2024 |
| 1.0.7 | 174 | 1/20/2024 |
| 1.0.5 | 175 | 1/19/2024 |
| 1.0.4 | 165 | 1/19/2024 |
| 1.0.2 | 169 | 1/19/2024 |
| 1.0.1 | 171 | 1/19/2024 |
| 1.0.0 | 186 | 1/19/2024 |
| 0.1.9 | 164 | 1/19/2024 |