英文:
Blazor - Fluxor - State not showing update
问题
以下是翻译好的内容,代码部分未翻译:
I'm new to Blazor and Fluxor. I'm having this issue: when I'm updating the state in one component, the updated state is not shown in a different component.
Actually, the initial state is an empty list. When I debug the reducer, the state is being updated correctly. I can see this, when I change the state the second time, I can see that the state is filled with the former action. But in a different component, the state seems to be empty still. I'm sure I miss something.
This is my component ComboboxFilterOption.razor
where the state is being updated:
<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 value=@comboboxItem.Value>@comboboxItem.DisplayValue</option>
}
}
</select>
</div>
</div>
@if (FilterValue != null)
{
<div class="row">
<div class="col">
Selected value: @FilterValue
</div>
</div>
}
</div>
This is the code-behind file of 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);
}
}
}
This is the reducer of 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;
}
}
}
The reducer seems to be working fine, because as described above it is filled, when I call it the second time. Here a screenshot where you can see, that it is filled:
It is also showing in Redux Dev Tools:
Here is the code from the different component (Filter.razor
), where I want to show the current 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" },
};
}
I did the Fluxor - Blazor Web Tutorial on https://github.com/mrpmorris/Fluxor/tree/master/Source/Tutorials/02-Blazor/02A-StateActionsReducersTutorial with the Counter
example. This example is working fine! So I assume it is not a general issue of the integration of Fluxor.
I actually cannot see why it does not show the current state.
英文:
I'm new to Blazor and Fluxor. I'm having this issue: when I'm updating the state in one component, the updated state is not shown in a different component.
Actually, the initial state is an empty list. When I debug the reducer, the state is being updated correctly. I can see this, when I change the state the second time, I can see that the state is filled with the former action. But in a different component, the state seems to be empty still. I'm sure I miss something.
This is my component ComboboxFilterOption.razor
where the state is being updated:
<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 value=@comboboxItem.Value>@comboboxItem.DisplayValue</option>
}
}
</select>
</div>
</div>
@if (FilterValue != null)
{
<div class="row">
<div class="col">
Selected value: @FilterValue
</div>
</div>
}
</div>
This is the code-behind file of 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);
}
}
}
This is the reducer of 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;
}
}
}
The reducer seems to be working fine, because as described above it is filled, when I call it the second time. Here a screenshot where you can see, that it is filled:
It is also showing in Redux Dev Tools:
Here is the code from the different component (Filter.razor
), where I want to show the current 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" },
};
}
I did the Fluxor - Blazor Web Tutorial on https://github.com/mrpmorris/Fluxor/tree/master/Source/Tutorials/02-Blazor/02A-StateActionsReducersTutorial with the Counter
example. This example is working fine! So I assume it is not a general issue of the integration of Fluxor.
I actually cannot see why it does not show the current state.
答案1
得分: 1
我找到了原因。错误在于 reducer 部分。
我需要创建一个 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);
}
英文:
I found the reason. The error was on the reducer.
I need to create a new instance of FilterState
instead of returning and modifying the old, updated state.
Before (WRONG!):
[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;
}
CORRECT / WORKING version:
[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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论