Ste*_*lis 7 blazor blazor-webassembly
我刚刚在 Blazor WebAssembly 中完成了第一个重要的测试应用程序。Blazor 是令人印象深刻的东西,但我发现很难推理属性的更改如何导致 DOM 更新 - 例如,在 Razor 组件中引用该属性。
<div>@SomeProperty</div>
Run Code Online (Sandbox Code Playgroud)
public int SomeProperty {get;set;}
Run Code Online (Sandbox Code Playgroud)
在 WPF 中,很容易推断更改如何流动并导致呈现更改,因为它们是由事件和 DependencyProperty 更改触发的。您可以看到这些并绑定到它们。在 Blazor 中,您可以通过某种方式更改属性值并更新页面。这背后的精确机制有点像魔术。因此,很难推断如何删除复杂组件的不必要更新。
谁能解释一下这个主题的基础?
是否有任何文档或视频深入探讨 Blazor 的这一领域?
MrC*_*tis 10
谁能解释一下这个主题的基础?
要了解更新过程,您需要了解组件。我会尽量保持简短!
所有组件都必须实现IComponent. ComponentBase是一个实现IComponent。
public interface IComponent
{
void Attach(RenderHandle renderHandle);
Task SetParametersAsync(ParameterView parameters);
}
Run Code Online (Sandbox Code Playgroud)
RenderHandle 的重要部分是:
public readonly struct RenderHandle
{
public Dispatcher Dispatcher ....
//....
public void Render(RenderFragment renderFragment)
{
//....
_renderer.AddToRenderQueue(_componentId, renderFragment);
//...
}
}
Run Code Online (Sandbox Code Playgroud)
RenderFragment 是:
public delegate void RenderFragment(RenderTreeBuilder builder);
Run Code Online (Sandbox Code Playgroud)
ARenderer管理渲染过程。它保存表示为 RenderTree 的 DOM(由浏览器渲染的内容)。当渲染器将组件附加到渲染树时,渲染器会创建RenderHandle并通过调用将其传递给组件Attach。组件使用它RenderHandle与渲染器进行通信。渲染器通过调用 与组件进行通信SetParametersAsync。
组件通过调用Render方法RenderHandle并传递RenderFragment委托来“渲染”。
这是一个简单的渲染片段:
protected RenderFragment HelloWorld => (RenderTreeBuilder builder) =>
{
builder.OpenElement(0, "div");
builder.AddContent(1, "Hello Blazor");
builder.CloseElement();
};
Run Code Online (Sandbox Code Playgroud)
调用不会Render渲染组件。它只是将渲染片段放入渲染器队列中。当渲染器运行片段时,它会检查其他组件引用的组件参数更改。它调用其参考参数已更改的任何组件。RenderHandle SetParametersAsync
StateHasChanged是一种ComponentBase方法。 StateHasChanged由 Blazor UI 事件处理程序内部调用,因此您很少需要手动调用它。如果你这样做,问问自己为什么?你的逻辑可能是错误的!它看起来像这样:
var task = InvokeAsync(EventMethod);
StateHasChanged();
if (!task.IsCompleted)
{
await task;
StateHasChanged();
}
Run Code Online (Sandbox Code Playgroud)
主要的异常是普通的事件处理程序。如果该事件更新组件中的数据,您需要通过调用 来触发手动更新StateHasChanged。这是标准模式。
private void OnSomethingChanged(object? sender, EventArgs e)
=> this.InvokeAsync(StateHasChanged);
Run Code Online (Sandbox Code Playgroud)
笔记:
StateHasChanged有一种机制可以检测渲染片段是否已排队,因此它不会对多个渲染进行排队。InvokeAsync确保任务在 UI 线程上运行。它使用Dispatcher上提供的RenderHandle。ComponentBase如果您想进一步挖掘,请深入研究-您可以在此处查看代码。
在 Blazor 中,您可以通过某种方式更改属性值并更新页面。
不完全是。房产本身与此无关。例如,您可以使用计时器更新它,并且您不会看到 UI 发生变化。
但通常您会设置该属性以响应 ButtonClick 或其他 Blazor(生命周期)事件。这些都用对 StateHasChanged() 的调用括起来。在 Timer 事件或其他非 Blazor 事件中,您必须自己调用 StateHasChanged()。
StateHasChanged()请求(不是:执行)UI 更新。该更新将在活动结束后或下一次活动期间进行await。
因此,很难推断如何删除复杂组件的不必要更新。
这与 不同<div>@SomeProperty</div>。
当您拥有<Details ItemId="itemId" />并且itemId是像 int 或字符串这样的基本类型时,只有当 itemId 更改时,才会重新渲染详细信息。
但是,当它是<Details Item="item" />并且 item 是某种复杂类型时,组件将始终与父页面一起重新呈现。
当 Item 没有可变属性时,我有时会在“详细信息”组件中使用以下模式,即 for <Details Item="selectedItem" />:
[Parameter]
public Item Item { get; set; } = new();
int oldId = 0;
protected override bool ShouldRender()
{
if (oldId != Item.Id)
{
oldId = Item.Id;
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3843 次 |
| 最近记录: |