C# 与3个子组件(fluxor)共享状态和处理事件

C# 与3个子组件(fluxor)共享状态和处理事件,c#,blazor,flux,blazor-webassembly,fluxor,C#,Blazor,Flux,Blazor Webassembly,Fluxor,我对fluxor及其基于的redux/flux模式还不熟悉。我目前正在从事Blazor wasm项目。 我选择使用fluxor进行状态管理。但我想知道如何处理以下情况: 当页面被加载时,组件1被来自API的数据通过fluxor状态管理填充 组件1是一个列表,其中包含用户可以选择的项目。单击时,所述项目应从API中检索,并在组件3中完整显示。组件2中显示了表示活动项的文本 组件2是一个导航器,使用简单的后退和下一步按钮浏览列表。单击“下一步”时,组件3应从API中检索下一项并完整显示该项。然后,组

我对fluxor及其基于的redux/flux模式还不熟悉。我目前正在从事Blazor wasm项目。 我选择使用fluxor进行状态管理。但我想知道如何处理以下情况:

当页面被加载时,组件1被来自API的数据通过fluxor状态管理填充

组件1是一个列表,其中包含用户可以选择的项目。单击时,所述项目应从API中检索,并在组件3中完整显示。组件2中显示了表示活动项的文本

组件2是一个导航器,使用简单的后退和下一步按钮浏览列表。单击“下一步”时,组件3应从API中检索下一项并完整显示该项。然后,组件1通过显示所选的列表项来反映此更改


我确实有行动等,以获得完整的项目。我只是不知道从哪里发送。或者如何确保所有组件都知道活动项是什么。对于纯blazor,我将通过所有事件回调来完成这项工作,并在本地处理活动项状态。但这将打破fluxor的观点

如果这些组件都是用于浏览客户机数据的单个用例的不同部分,那么我会将它们全部放在单个功能中

假设您有以下来自API的合同类

public class ClientSummary
{
  public Guid ID { get; set; }
  public string Name { get; set; }
}

public class ClientDetails
{
  public Guid ID { get; set; }
  public string Name { get; set; }
  public string LotsOfOtherInfo { get; set; }
  public string ArchivedInfo { get; set; }  
}

注意:就我个人而言,我会给他们提供私有setter,并使用Newtonsoft反序列化API响应。这将确保它们是不可变的,并且您可以在状态中直接使用它们,而无需创建两个类来使您的状态不可变

您的功能状态可能如下所示

public class MyUseCaseState
{
  public bool IsLoadingList { get; }
  public ReadOnlyCollection<ClientSummary> Summaries { get; }
  public int SelectedClientIndex { get; }

  public bool IsLoadingDetails { get; }
  public ClientDetails ClientDetails { get; }

  public MyUseCaseState(
    bool isLoadingList, 
    IEnumerable<ClientSummary> summaries, 
    int selectedClientIndex, 
    bool isLoadingDetails, 
    ClientDetails clientDetails)
  {
    IsLoadingList = isLoadingList;
    Summaries = (summaries ?? Enumerable.Empty<ClientSummary>()).ToList().AsReadOnly();
    SelectedClientIndex = selectedClientIndex;
    IsLoadingDetails = isLoadingDetails;
    ClientDetails = clientDetails;
  }
}
减速器将清除列表并将索引设置为-1

[ReducerMethod]
public static MyUseCaseState ReduceLoadClientListAction(MyUseCaseState state, LoadClientListAction action)
=> new MyUseCaseState(
     isLoadingList: true,
     summaries: null,
     selectedClientIndex: -1,
     isLoadingDetails: false,
     clientDetails: null
   );
您的效果将转到服务器以获取列表,然后通过操作推送到状态

[EffectMethod]
public async Task HandleLoadClientListAction(LoadClientListAction action, IDispatcher dispatcher)
{
  ClientSummary[] clientSummaries = await GetFromApi.....;
  ClientSummary firstClient = clientSummaries.FirstOrDefault();
  var result = new LoadClientListResultAction(clientSummaries, firstClient);
  dispatcher.Dispatch(result);
}
此操作的还原方法

[ReducerMethod]
public static MyUseCaseState ReduceLoadClientListResultAction(MyUseCaseState state, LoadClientListResultAction action)
=> new MyUseCaseState(
     isLoadingList: false,
     summaries: action.Summaries,
     selectedClientIndex: action.Summaries.Count == 0 ? -1 : 0,
     isLoadingDetails: false,
     clientDetails: action.FirstClient
   );
现在,您需要在SelectedClientIndex更改或列表加载时加载所选客户端的数据。您只需执行一个操作即可设置所选索引

@inject IState<MyUseCaseState> MyUseCaseState

Dispatcher.Dispatcher(new SelectIndexAction(MyUseCaseState.Value.SelectedClientIndex + 1));
获取数据的效果

[EffectMethod]
public async Task HandleSelectIndexAction(SelectIndexAction action, IDispatcher dispatcher)
{
  ClientDetails details = await GetFromYourApi....
  var result = new SelectIndexResultAction(details);
  dispatcher.Dispatch(result);
}
最后更新你的状态

[ReducerMethod]
public static MyUseCaseState ReduceSelectIndexAction(MyUseCaseState state, SelectIndexResultAction action)
=> new MyUseCaseState(
     isLoadingList: state.IsLoadingList,
     summaries: state.Summaries,
     selectedClientIndex: state.SelectedIndex,
     isLoadingDetails: false,
     clientDetails: action.ClientDetails
   );

谢谢这应该行得通。如果我可以问一下,为什么您也将ClientDetails放在同一个功能中?因为它是同一个用例的一部分。用例是我想看到一个客户机列表。我想查看选择的第一个客户端。我希望能够导航下一个/上一个客户端,并且为了从服务器获取详细信息并在导航离开此页面时显示,可以安全地清除该功能中的所有状态,因为您知道它不再被使用。如果ClientState是共享的,那么你永远不可能知道清除它是安全的。基于用例复制状态比共享状态更好,因为这会导致内存泄漏。1在我看来,以Flux/Redux风格编写的应用程序中的错误是人们共享状态。因为你不知道什么时候可以清除共享状态,你最终永远不会清除它。您的内存消耗一直在增长——您必须实现某种方式让服务器告诉您其他用户删除了哪些客户端,这样您就不会将删除的对象也保持在您的状态。最好每个用例复制数据,这样每个用例都有自己的状态,并且可以清除。它的减速器可以对其他功能的动作做出反应以保持一致。
[EffectMethod]
public async Task HandleSelectIndexAction(SelectIndexAction action, IDispatcher dispatcher)
{
  ClientDetails details = await GetFromYourApi....
  var result = new SelectIndexResultAction(details);
  dispatcher.Dispatch(result);
}
[ReducerMethod]
public static MyUseCaseState ReduceSelectIndexAction(MyUseCaseState state, SelectIndexResultAction action)
=> new MyUseCaseState(
     isLoadingList: state.IsLoadingList,
     summaries: state.Summaries,
     selectedClientIndex: state.SelectedIndex,
     isLoadingDetails: false,
     clientDetails: action.ClientDetails
   );