Я новичок в Blazor и Fluxor. У меня такая проблема: когда я обновляю состояние в одном компоненте, обновленное состояние не отображается в другом компоненте.
На самом деле начальное состояние — это пустой список. Когда я отлаживаю редуктор, состояние обновляется правильно. Я вижу это, когда я меняю состояние во второй раз, я вижу, что состояние заполнено прежним действием. Но в другом компоненте состояние кажется пустым. Я уверен, что что-то пропустил.
Это мой компонент ComboboxFilterOption.razor
, состояние которого обновляется:
<div class = "card p-2 @IsFilterActiveCssClass">
<div class = "row">
<div class = "col">
@FilterName
</div>
</div>
<div class = "row">
<div class = "col">
<select class = "form-control"
@onchange = "OnChange"
>
<option value = "-1">Please select</option>
@if (ComboboxItems != null)
{
@foreach (var comboboxItem in ComboboxItems)
{
<option [email protected]>@comboboxItem.DisplayValue</option>
}
}
</select>
</div>
</div>
@if (FilterValue != null)
{
<div class = "row">
<div class = "col">
Selected value: @FilterValue
</div>
</div>
}
</div>
Это файл кода программной части ComboboxFilterOption.razor
using Fluxor;
using GUI.Data;
using GUI.Store.Actions;
using GUI.Store.FilterUseCase;
using Microsoft.AspNetCore.Components;
namespace GUI.Shared.Components.Filter
{
public partial class ComboboxFilterOption
{
[Inject]
private IState<FilterState> FilterState { get; set; }
[Inject]
public IDispatcher Dispatcher { get; set; }
[Parameter] public string FilterName { get; set; } = string.Empty;
[Parameter] public string InternalFilterName { get; set; } = string.Empty;
[Parameter] public List<Data.ComboboxItem>? ComboboxItems { get; set; }
private Enums.FilterType FilterType = Enums.FilterType.Combobox;
private string? FilterValue;
private List<Data.FilterOperator>? FilterOperators = Data.FilterOperator.GetOperatorsForType(Enums.FilterType.Combobox);
private string IsFilterActiveCssClass = string.Empty;
private void OnChange(ChangeEventArgs e)
{
FilterValue = e.Value?.ToString();
string newFilterActiveValue = string.Empty;
if (!string.IsNullOrEmpty(FilterValue) && FilterValue != "-1")
{
newFilterActiveValue = "bg-success text-white";
}
IsFilterActiveCssClass = newFilterActiveValue;
Data.Filter updatedFilter = new Data.Filter()
{
InternalName = InternalFilterName,
Type = FilterType,
Operator = new FilterOperator() { Name = "Equals", Number = 1 },
Value = FilterValue
};
var action = new UpdateFilterAction(updatedFilter);
Dispatcher.Dispatch(action);
}
}
}
Это редуктор FilterState
:
using Fluxor;
using GUI.Store.Actions;
namespace GUI.Store.FilterUseCase
{
public static class Reducers
{
[ReducerMethod]
public static FilterState ReduceUpdateFilterAction(FilterState state, UpdateFilterAction action)
{
var alreadySetFilter = state.Filters.Where((filter) => filter.InternalName == action.Filter.InternalName).FirstOrDefault();
if (alreadySetFilter != null)
{
var index = state.Filters.IndexOf(alreadySetFilter);
state.Filters[index] = action.Filter;
}
else
{
state.Filters.Add(action.Filter);
}
return state;
}
}
}
Редьюсер вроде нормально работает, потому что как описано выше он заполняется, когда я вызываю его второй раз. Вот скриншот, где видно, что он заполнен:
Это также отображается в Redux Dev Tools:
Вот код из другого компонента (Filter.razor
), где я хочу показать текущий FilterState
@using Fluxor;
@using GUI.Store.Actions;
@using GUI.Store.FilterUseCase;
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
<div class = "container-fluid">
<div class = "row">
<div class = "col">
<GUI.Shared.Components.Filter.ComboboxFilterOption
InternalFilterName = "ProductStatus"
FilterName = "Status"
ComboboxItems=ProductStatus
/>
</div>
</div>
<div>FilterStateCount @FilterState.Value.Filters.Count()</div>
@foreach (Data.Filter filter in FilterState.Value.Filters)
{
<div class = "row">
<div class = "col">
@filter.InternalName: @filter.Value
</div>
</div>
}
</div>
@code {
[Inject]
private IState<FilterState> FilterState { get; set; }
[Inject]
public IDispatcher Dispatcher { get; set; }
private List<Data.ComboboxItem> ProductStatus = new List<Data.ComboboxItem>()
{
new Data.ComboboxItem() { Value = 1, DisplayValue = "DUMMY DATA - INTRO" },
new Data.ComboboxItem() { Value = 2, DisplayValue = "DUMMY DATA - ACTIVE" },
new Data.ComboboxItem() { Value = 3, DisplayValue = "DUMMY DATA - DORMANT" },
new Data.ComboboxItem() { Value = 4, DisplayValue = "DUMMY DATA - STOP FLAGGED" },
};
}
Я сделал веб-учебник Fluxor — Blazor на https://github.com/mrpmorris/Fluxor/tree/master/Source/Tutorials/02-Blazor/02A-StateActionsReducersTutorial с примером Counter
. Этот пример работает нормально! Поэтому я предполагаю, что это не общая проблема интеграции Fluxor.
На самом деле я не понимаю, почему он не показывает текущее состояние.
Я нашел причину. Ошибка была на редукторе.
Мне нужно создать новый экземпляр FilterState
вместо того, чтобы возвращать и изменять старое обновленное состояние.
До (НЕПРАВИЛЬНО!):
[ReducerMethod]
public static FilterState ReduceUpdateFilterAction(FilterState state, UpdateFilterAction action)
{
var alreadySetFilter = state.Filters.Where((filter) => filter.InternalName == action.Filter.InternalName).FirstOrDefault();
if (alreadySetFilter != null)
{
var index = state.Filters.IndexOf(alreadySetFilter);
state.Filters[index] = action.Filter;
}
else
{
state.Filters.Add(action.Filter);
}
return state;
}
ПРАВИЛЬНАЯ/РАБОТАЮЩАЯ версия:
[ReducerMethod]
public static FilterState ReduceUpdateFilterAction(FilterState state, UpdateFilterAction action)
{
var newList = state.Filters;
var alreadySetFilter = newList.Where((filter) => filter.InternalName == action.Filter.InternalName).FirstOrDefault();
if (alreadySetFilter != null)
{
var index = newList.IndexOf(alreadySetFilter);
newList[index] = action.Filter;
}
else
{
newList.Add(action.Filter);
}
return new FilterState(newList);
}