Blazor – Fluxor – 状态未显示更新

huangapple go评论54阅读模式
英文:

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:

Blazor – Fluxor – 状态未显示更新

It is also showing in Redux Dev Tools:

Blazor – Fluxor – 状态未显示更新

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:

&lt;div class=&quot;card p-2 @IsFilterActiveCssClass&quot;&gt;
    &lt;div class=&quot;row&quot;&gt;
        &lt;div class=&quot;col&quot;&gt;
            @FilterName
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;row&quot;&gt;
        &lt;div class=&quot;col&quot;&gt;
            &lt;select class=&quot;form-control&quot;
            @onchange=&quot;OnChange&quot;
        &gt;
                &lt;option value=&quot;-1&quot;&gt;Please select&lt;/option&gt;
                @if (ComboboxItems != null)
                {
                    @foreach (var comboboxItem in ComboboxItems)
                    {
                        &lt;option value=@comboboxItem.Value&gt;@comboboxItem.DisplayValue&lt;/option&gt;
                    }
                }
            &lt;/select&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    @if (FilterValue != null)
    {
        &lt;div class=&quot;row&quot;&gt;
            &lt;div class=&quot;col&quot;&gt;
                Selected value: @FilterValue
            &lt;/div&gt;
        &lt;/div&gt;
    }
&lt;/div&gt;

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&lt;FilterState&gt; 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&lt;Data.ComboboxItem&gt;? ComboboxItems { get; set; }

        private Enums.FilterType FilterType = Enums.FilterType.Combobox;
        private string? FilterValue;
        private List&lt;Data.FilterOperator&gt;? 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) &amp;&amp; FilterValue != &quot;-1&quot;)
            {
                newFilterActiveValue = &quot;bg-success text-white&quot;;
            }
            IsFilterActiveCssClass = newFilterActiveValue;
            Data.Filter updatedFilter = new Data.Filter()
            {
                InternalName = InternalFilterName,
                Type = FilterType,
                Operator = new FilterOperator() { Name = &quot;Equals&quot;, 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) =&gt; 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:

Blazor – Fluxor – 状态未显示更新

It is also showing in Redux Dev Tools:

Blazor – Fluxor – 状态未显示更新

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

&lt;div class=&quot;container-fluid&quot;&gt;
    &lt;div class=&quot;row&quot;&gt;
        &lt;div class=&quot;col&quot;&gt;
            &lt;GUI.Shared.Components.Filter.ComboboxFilterOption
                InternalFilterName=&quot;ProductStatus&quot;
                FilterName=&quot;Status&quot;
                ComboboxItems=ProductStatus
            /&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div&gt;FilterStateCount @FilterState.Value.Filters.Count()&lt;/div&gt;
    @foreach (Data.Filter filter in FilterState.Value.Filters)
    {
        &lt;div class=&quot;row&quot;&gt;
            &lt;div class=&quot;col&quot;&gt;
                @filter.InternalName: @filter.Value
            &lt;/div&gt;
        &lt;/div&gt;
    }
&lt;/div&gt;

@code {
    [Inject]
    private IState&lt;FilterState&gt; FilterState { get; set; }
    [Inject]
    public IDispatcher Dispatcher { get; set; }

    private List&lt;Data.ComboboxItem&gt; ProductStatus = new List&lt;Data.ComboboxItem&gt;()
    {
        new Data.ComboboxItem() { Value = 1, DisplayValue = &quot;DUMMY DATA - INTRO&quot; },
        new Data.ComboboxItem() { Value = 2, DisplayValue = &quot;DUMMY DATA - ACTIVE&quot; },
        new Data.ComboboxItem() { Value = 3, DisplayValue = &quot;DUMMY DATA - DORMANT&quot; },
        new Data.ComboboxItem() { Value = 4, DisplayValue = &quot;DUMMY DATA - STOP FLAGGED&quot; },
    };
}

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) =&gt; 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) =&gt; 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);
}

huangapple
  • 本文由 发表于 2023年3月31日 17:53:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75897135.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定