ReduxDotnet 0.2.0
dotnet add package ReduxDotnet --version 0.2.0
NuGet\Install-Package ReduxDotnet -Version 0.2.0
此命令旨在在 Visual Studio 的包管理器控制台中使用,因为它使用 NuGet 模块的 Install-Package 版本。
<PackageReference Include="ReduxDotnet" Version="0.2.0" />
对于支持 PackageReference 的项目,将此 XML 节点复制到项目文件中以引用包。
paket add ReduxDotnet --version 0.2.0
NuGet 团队不提供对此客户端的支持。请联系其 管理员 以获得支持。
#r "nuget: ReduxDotnet, 0.2.0"
#r 指令可用于 F# Interactive 和 Polyglot Notebooks。将此复制到交互式工具或脚本的源代码中引用包。
// Install ReduxDotnet as a Cake Addin #addin nuget:?package=ReduxDotnet&version=0.2.0 // Install ReduxDotnet as a Cake Tool #tool nuget:?package=ReduxDotnet&version=0.2.0
NuGet 团队不提供对此客户端的支持。请联系其 管理员 以获得支持。
ReduxDotnet
这是一个简单的,但对于 .NET 6 来说是足够的 Redux 实现。
https://nuget.net.cn/packages/ReduxDotnet
如何使用它
创建状态、操作、减法器和效果。
// Define app state
record AppState(int Count);
// Define actions
record IncrementAction();
record DecrementAction();
// Define reducer
class Reducers :
IReducer<AppState, IncrementAction>,
IReducer<AppState, DecrementAction>
{
public AppState Invoke(AppState store, IncrementAction action) =>
store with { Count = store.Count + 1 };
public AppState Invoke(AppState store, DecrementAction action) =>
store with { Count = store.Count - 1 };
}
// Define effects (If you want to use async operation)
class Effects
{
public EffectDelegate<AppState> IncrementLater() => async (d) =>
{
await Task.Delay(2000);
d.Dispatch(new IncrementAction());
};
}
让我们将这些应用于您的应用程序。ReduxDotnet 旨在与 Microsoft.Extensions.DependencyInjection
一起使用。
using Microsoft.Extensions.DependencyInjection;
using Reactive.Bindings;
using ReduxDotnet;
var services = new ServiceCollection();
// init ReduxDotnet with initial status
services.AddReduxDotnet<AppState>(new AppState(0));
// Add reducers and effects
services.AddReducer<AppState, Reducers>();
services.AddSingleton<Effects>();
var provider = services.BuildServiceProvider();
// AppStore is IReactiveProperty<AppState>.
var store = provider.GetRequiredService<IReactiveProperty<AppState>>();
store.Subscribe(x =>
Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss}: Status was changed {x}."));
// Dispatcher and Effects
var dispatcher = provider.GetRequiredService<IDispatcher<AppState>>();
var effects = provider.GetRequiredService<Effects>();
// Dispatch actions
dispatcher.Dispatch(new IncrementAction());
dispatcher.Dispatch(new IncrementAction());
dispatcher.Dispatch(new DecrementAction());
// Async operation
await dispatcher.DispatchAsync(effects.IncrementLater());
输出
2022-04-22 22:13:05: Status was changed AppState { Count = 0 }.
2022-04-22 22:13:05: Status was changed AppState { Count = 1 }.
2022-04-22 22:13:05: Status was changed AppState { Count = 2 }.
2022-04-22 22:13:05: Status was changed AppState { Count = 1 }.
2022-04-22 22:13:07: Status was changed AppState { Count = 2 }.
如何在 Blazor WASM(Blazer 服务器也行)上使用它
创建状态
创建您的应用程序状态。在 .NET 6 上,您可以使用记录或记录结构,如下所示。
namespace ReduxDotnetSample.Store;
public record AppState(int Count);
创建动作
动作仅是普通的 C# 类或结构。您也可以使用记录或记录结构来创建动作。
// IncrementAction.cs
namespace ReduxDotnetSample.Actions;
public record IncrementAction(int Amount);
// DecrementAction.cs
namespace ReduxDotnetSample.Actions;
public record DecrementAction(int Amount);
创建减法器
减法器是实现 IReducer<TStore, TAction>
接口的类。类型参数 TStore
是您创建的应用程序状态类。而 TAction
是您想在减法器类上处理的动作类型。
您还可以将多个 IReducer<TStore, TAction>
实现任意为一个类,如下所示。
using ReduxDotnet;
using ReduxDotnetSample.Actions;
using ReduxDotnetSample.Store;
namespace ReduxDotnetSample.Reducers;
public class AppReducers :
IReducer<AppState, IncrementAction>,
IReducer<AppState, DecrementAction>
{
public AppState Invoke(AppState store, IncrementAction action) =>
store with { Count = store.Count + action.Amount };
public AppState Invoke(AppState store, DecrementAction action) =>
store with { Count = store.Count - action.Amount };
}
创建影响
如果您想处理异步操作,则可以使用效果来实现。效果只是返回 EffectDelegate<TStore>
的方法。 EffectDelegate<TStore>
定义如下+
namespace ReduxDotnet;
public delegate ValueTask EffectDelegate<TStore>(IDispatcher<TStore> dispatcher, Func<TStore> getStore);
以下是一个将计数器属性增加后 2 秒钟的效果
using ReduxDotnet;
using ReduxDotnetSample.Actions;
using ReduxDotnetSample.Store;
namespace ReduxDotnetSample.Effects;
public class AppEffects
{
public EffectDelegate<AppState> IncrementAsync(int amount) => async (dispatcher) =>
{
await Task.Delay(2000);
dispatcher.Dispatch(new IncrementAction(amount));
};
}
将所有创建的都注册到 IServiceCollection
所有实现都已完成!最后一步是将所有内容注册到 IServiceCollection
中,以便在您的应用程序中使用。
// Register IReactiveProperty<AppState> and IDispatcher<AppState> as singleton.
builder.Services.AddReduxDotnet(new AppState(0));
// Register Reducers for Dispatcher.
builder.Services.AddReducer<AppState, AppReducers>();
// Effects are plain C# classes, so you can register to IServiceCollection same as other classes.
builder.Services.AddSingleton<AppEffects>();
让我们在 Counter 页面上使用它
Counter 的 razor 文件与没有 Redux 的一个相同。
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<div>
<label for="amount">Amount</label>
<input id="amount" type="text" @bind="Amount" />
</div>
<p role="status">Current count: @CurrentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Increment</button>
<button class="btn btn-primary" @onclick="DecrementCount">Decrement</button>
<button class="btn btn-primary" @onclick="IncrementCountAfterTwoSecondsAsync">Increment (Async)</button>
Counter.razor.cs 与典型的一个不同。AppState 被用作 IReactiveProperty
。你可以看到 IDispatcher
。这是一个Redux的调度器类。然后_appEffects 适用于异步操作。
using Microsoft.AspNetCore.Components;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using ReduxDotnet;
using ReduxDotnetSample.Actions;
using ReduxDotnetSample.Effects;
using ReduxDotnetSample.Store;
using System.ComponentModel.DataAnnotations;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
namespace ReduxDotnetSample.Pages;
public partial class Counter : IDisposable
{
private readonly CompositeDisposable _disposables = new();
[Inject]
public IReactiveProperty<AppState> Store { get; set; } = default!;
[Inject]
public IDispatcher<AppState> Dispatcher { get; set; } = default!;
[Inject]
public AppEffects AppEffects { get; set; } = default!;
public int CurrentCount => Store.Value.Count;
private int Amount { get; set; } = 1;
protected override void OnInitialized()
{
// Observe Count value and if it was changed, then call StateHasChanged to refresh UI.
Store.Select(x => x.Count)
.DistinctUntilChanged()
.Subscribe(x =>
{
_ = InvokeAsync(() => StateHasChanged());
})
.AddTo(_disposables);
}
public void Dispose() => _disposables.Dispose();
private void IncrementCount()
{
// Dispatch IncrementAction to reducers
Dispatcher.Dispatch(new IncrementAction(Amount));
}
private void DecrementCount()
{
// Dispatch DecrementAction to reducers
Dispatcher.Dispatch(new DecrementAction(Amount));
}
private async Task IncrementCountAfterTwoSecondsAsync()
{
// Async operation is dispatched using DispatchAsync method and EffectDelegate<TStore>.
await Dispatcher.DispatchAsync(AppEffects.IncrementAsync(Amount));
}
}
它的工作方式如下
产品 | 版本 兼容性和额外的目标框架计算版本。 |
---|---|
.NET | net6.0 兼容。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 已计算。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 已计算。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。 |
-
net6.0
- Microsoft.Extensions.DependencyInjection (>= 6.0.0)
- ReactiveProperty.Core (>= 8.0.5)
NuGet 包
此包未被任何NuGet包使用。
GitHub 仓库
此包未被任何流行的GitHub仓库使用。