Blazor - SetParameters - 为啥字符串参数绑定的行为与复杂类型不同

Posted

技术标签:

【中文标题】Blazor - SetParameters - 为啥字符串参数绑定的行为与复杂类型不同【英文标题】:Blazor - SetParameters - why string parameter binding behaves differently from a complex typeBlazor - SetParameters - 为什么字符串参数绑定的行为与复杂类型不同 【发布时间】:2021-08-20 07:50:31 【问题描述】:

考虑带有字符串参数和复杂类型参数的子组件。

<Child Name="@strProperty" />
<Child Model="@compelexType" />

假设两个参数都没有改变,在父组件上调用 StateHasChanged 会导致具有复杂参数的子组件重新渲染,而不是字符串参数。

查看此演示:https://blazorrepl.com/repl/wbYguGuA515uMYR742

你如何解释不同的行为?

【问题讨论】:

Docs: "如果满足以下任一条件,则从 ComponentBase 继承的组件会因参数更新而跳过重新渲染:...所有参数值都是已知的不可变 primitive类型,例如 int、string、DateTime 和 自从设置了上一组参数后没有改变,..." 我会接受这个作为答案 【参考方案1】:

这本身不是一个答案,我只是需要比评论更多的空间。

我认为引用的文档不能完全解释观察到的结果。

文件指出:

默认情况下,Razor 组件继承自 ComponentBase 基类,其中包含在以下时间触发重新渲染的逻辑:

    从父组件应用一组更新的参数后。 为级联参数应用更新值后。 在通知事件并调用其自己的事件处理程序之一之后。 在调用其自己的 StateHasChanged 方法后(请参阅 ASP.NET Core Razor 组件生命周期)。

这些都是内部操作。前两个发生在组件上调用 SetParametersAsync 之后。最后两个来自组件内部的操作。

任何子组件活动,例如重新渲染,都是由Renderer 调用SetParametersAsync 触发的,而不是直接由父组件触发。 Renderer 根据检测到的对任何子组件 Parameter 的更改做出此决定。所以发生重新渲染的原因是因为Renderer 决定它是一个对象而不是原始类型,与ComponentBase 无关。

为了证明这一点,我基于IComponent 而不是ComponentBase 编写了一个非常基本的组件。它看起来像这样:

using Blazor.Starter.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using System.Threading.Tasks;

namespace Blazor.Starter.Components.TestComponents

    public class ObjectTest : IComponent
    
        [Parameter] public DataModel Model  get; set; 

        [Parameter] public int Value  get; set; 

        private RenderHandle _renderHandle;
        private int _renders;

        public void Attach(RenderHandle renderHandle)
        
            _renderHandle = renderHandle;
        

        public Task SetParametersAsync(ParameterView parameters)
        
            parameters.SetParameterProperties(this);
            _renders++;
            this.Render();
            return Task.CompletedTask;
        

        public void Render()
            => _renderHandle.Render(RenderComponent);

        private void RenderComponent(RenderTreeBuilder builder)
        
            builder.OpenElement(0, "div");
            builder.AddContent(1, $"Rendered _renders");
            builder.CloseElement();
        

    

如果您在父级SetParametersAsync 中设置Model,则如果您只设置Value,则不会。结果一样。

【讨论】:

【参考方案2】:

Documentation:

如果满足以下任一条件,则从ComponentBase 继承的组件会因参数更新而跳过重新渲染:

所有参数值都是已知的不可变原始类型,例如intstringDateTime自从设置了上一组参数以来没有改变 组件的ShouldRender方法返回false

【讨论】:

【参考方案3】:

正如@GSerg 在评论中所说:这是因为原始属性没有改变,所以它没有更新。

【讨论】:

以上是关于Blazor - SetParameters - 为啥字符串参数绑定的行为与复杂类型不同的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 Android.harware.Camera 中的 setParameters 失败?

Android调用camera错误setParameters failed深层解析

Camera setParameters(), getParameters(),unlock()三个方法之间的限制关系

java mock http_Java MockHttpServletRequest.setParameters方法代码示例

使用 python 和 SL4A 初始化 android 网络摄像头时 setParameters 失败

MyBatis源码解读 - 使用SqlRunner操作数据库