【问题标题】:RenderFragment causing all same type components to updateRenderFragment 导致所有相同类型的组件更新
【发布时间】:2022-08-14 15:58:59
【问题描述】:

我在编写 Blazor 服务器组件时遇到了一些问题。我有一个在同一页面上多次使用的自定义组件。当任何一个组件的属性发生更改时,两个组件都会重新渲染/更新(如果在组件中使用了RenderFragment)。为什么是这样?如何修复它,以便只有正确组件上的属性才呈现该组件的更新,而不更新所有其他组件?

这只发生在使用RenderFragment 时。从组件中删除 RenderFragment@ChildContent 可解决此问题。

我创建了一个简单的示例来演示该问题。

page.razor

@page \"/\"

<div>
    <button @onclick=\"OnClick_Update_1\">Update 1</button>
    <button @onclick=\"OnClick_Update_2\">Update 2</button>
</div>
<h3>Component 1</h3>
<MyComponent PlayNice=\"DoUpdate_1\">ABC</MyComponent>

<h3>Component 2</h3>
<MyComponent PlayNice=\"DoUpdate_2\">DEF</MyComponent>

@code{
    private bool DoUpdate_1 { get; set; } = false;
    private bool DoUpdate_2 { get; set; } = false;

    private void OnClick_Update_1(){
        DoUpdate_1 = true;
    }

    private void OnClick_Update_2() {
        DoUpdate_2 = true;
    }
}

MyComponent.razor

<p class=\"@_class\">@ChildContent - @DateTime.UtcNow</p>

@code {
    [Parameter] public bool PlayNice { get; set; } = false;
    [Parameter] public RenderFragment ChildContent { get; set; } = default!;

    private string _class { get; set; } = default!;

    protected override void OnParametersSet() {
        _class = string.Empty;
        if (PlayNice)
            _class += \"abcdef\";
        base.OnParametersSet();
    }

}

此处提供了一个工作示例:https://blazorfiddle.com/s/facmehiz (交替单击按钮 - 两个组件都将更新)

没有 RenderFragment 的示例:https://blazorfiddle.com/s/0w11bbxw (是我想要的结果,但我想用一个RenderFragment)

谢谢你。

    标签: blazor blazor-server-side


    【解决方案1】:

    以下代码 sn-p 说明了如何一次渲染每个组件...每次单击“更新 1”时,MyComponent 的第一个实例会重新渲染。每次单击“更新 2”时,MyComponent 的第二个实例都会重新渲染。复制并测试...

    MyComponent.razor

    <p class="@_class">@ChildContent - @DateTime.UtcNow</p>
    
    @code {
        [Parameter] public bool PlayNice { get; set; }
    
        [Parameter] public EventCallback<bool> PlayNiceChanged { get; set; }
    
       
        [Parameter] public RenderFragment ChildContent { get; set; }
    
        private string _class { get; set; }
    
        protected override bool ShouldRender()
        {
            return PlayNice;
        }
    
        protected override void OnParametersSet()
        {
            _class = string.Empty;
            if (PlayNice)
            {
                PlayNiceChanged.InvokeAsync(false);
    
                _class += "abcdef";
            }
    
        }
    
    } 
    

    索引剃刀

    @page "/"
    
    <div>
        <button @onclick="OnClick_Update_1">Update 1</button>
        <button @onclick="OnClick_Update_2">Update 2</button>
    </div>
    <h3>Component 1</h3>
    <MyComponent @bind-PlayNice="DoUpdate_1">ABC</MyComponent>
    
    <h3>Component 2</h3>
    <MyComponent @bind-PlayNice="DoUpdate_2">DEF</MyComponent>
    
    @code{
        private bool DoUpdate_1 { get; set; } 
        private bool DoUpdate_2 { get; set; } 
    
        private void OnClick_Update_1()
        {
            DoUpdate_1 = true;
            
        }
    
        private void OnClick_Update_2()
        {
            DoUpdate_2 = true;
        
        }
    }
    

    【讨论】:

    • 太好了,谢谢enet。你的回答对我帮助很大。我已将此标记为已接受的答案。
    【解决方案2】:

    请注意,@onclick 事件会导致 Index.razor 组件重新呈现。然后 Blazor 必须决定应该更新哪些子组件。

    在第一种情况下,有两个“简单”类型的参数,字符串和布尔。 Blazor 可以并且将在这些更改时进行跟踪,在这种情况下仅重新渲染 PlayNice 更改的组件。

    在第二个示例中,有一个 RenderFragment 参数。 Blazor 在此处跟踪更改是不可行的,因此 Blazor 从不尝试和总是更新组件。
    MyModel 类型参数也会发生同样的情况。

    【讨论】:

    • RenderFragment 版本不一样吗?参数PlayNice 仍应被跟踪..?如果参数仅在其中一个组件上发生更改,我不明白为什么两个组件都会更新。我不确定我是否理解为什么 RenderFragment 会损坏其他参数的跟踪。
    • 因为 RenderFragment 是一种“复杂类型”,并且 Blazor 假定它总是在变化。 Even when empty
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 2015-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多