英文:
Should I be using SetParametersAsync() for all [Parameter] properties?
问题
以下是您要翻译的内容:
现在我正在使用 SetParametersAsync()
来处理一个 [Parameter]
,在调用 OnInitializedAsync()
时没有设置。但这让我思考...
即使是像 Visible
这样简单的属性,通常设置为 "true"
或 "false"
,有时也可以根据数据库查询进行设置,因此可能会在调用 OnInitializedAsync()
后设置。
那么... 我应该只在 SetParametersAsync()
中处理每个 [Parameter]
,而不是在 OnInitializedAsync()
中处理吗?
或者,如果它们不为空,我应该在 OnInitializedAsync()
中处理它们,并在 SetParametersAsync()
中监视它们是否发生了更改?
还有一个相关的问题。对于我在 SetParametersAsync()
中处理的每个参数,我是否需要保留上次设置的本地副本,以确定新值是否发生了变化?还是有办法询问 ParameterView
值是否发生了变化?(我在搜索中找不到任何信息。)
这是一个困难的问题(是否发生了变化),因为在这种情况下,它是一个 List<User>
,因此获取一个 "当 list.Count == prevList.Count 时新值并不意味着列表没有发生变化。"
英文:
I am now using SetParametersAsync()
for a [Parameter]
that is not set when OnInitializedAsync()
is called. But that led to my thinking...
Even a property as simple as Visible
, while usually set to "true"
or "false"
could sometimes be set based on a DB query and therefore get set after OnInitializedAsync()
is called.
So... should I handle every [Parameter]
only in SetParametersAsync()
and not in OnInitializedAsync()
Or, should I handle them in OnInitializedAsync()
if they're non-null and also watch for them being changed in SetParametersAsync()
And associated question. For each parameter I handle in SetParametersAsync()
, do I need to keep a local copy of what it was last set to, to determine if the new value is a change? Or is there a way I can ask ParameterView
if the value is changed? (I can't find anything in my searching.)
This is a difficult question (did it change) as in this case, it's a List<User> and so getting a "new value where list.Count == prevList.Count does not mean that the list didn't change.
答案1
得分: 3
Consider this code
<h3>TestComponent</h3>
<div class="bg-dark text-white m-2 p-2">
<pre>State : @this.State</pre>
</div>
@code {
[Parameter] public string? State { get; set; }
public override async Task SetParametersAsync(ParameterView parameters)
{
// emulate doing something async to get something before assigning the parameters
await Task.Delay(1);
parameters.SetParameterProperties(this);
await base.SetParametersAsync(ParameterView.Empty);
}
}
Looks plausible, but it will generate an error:
InvalidOperationException: The ParameterView instance can no longer be read because it has expired. ParameterView can only be read synchronously and must not be stored for later use.
Why, because the Renderer has moved on and the ParameterView
instance is potentially stale. You have yielded back to the Renderer, and all sorts of sync code may have run that changed data in the ParameterView
instance.
英文:
Consider this code
<h3>TestComponent</h3>
<div class="bg-dark text-white m-2 p-2">
<pre>State : @this.State</pre>
</div>
@code {
[Parameter] public string? State { get; set; }
public override async Task SetParametersAsync(ParameterView parameters)
{
// emulate doing something async to get something before assigning the parameters
await Task.Delay(1);
parameters.SetParameterProperties(this);
await base.SetParametersAsync(ParameterView.Empty);
}
}
Looks plausible, but it will generate an error:
InvalidOperationException: The ParameterView instance can no longer be read because it has expired. ParameterView can only be read synchronously and must not be stored for later use.
Why, because the Renderer has moved on and the ParameterView
instance is potentially stale. You have yielded back to the Renderer and all sorts of sync code may have run that changed data in the ParameterView
instance.
答案2
得分: 2
OnInitialized-
:
我会在这里为组件做好准备,很少与组件参数相关。我经常会设置用于 UI 基础逻辑或其他未在参数/字段上设置的内部或私有参数/字段。这些内容包括加载模态框的渲染、EditContext
等。如果我的组件没有参数,我会在这里添加所有起始逻辑。
OnParameterSet-
:
我会在这里添加所有组件参数的逻辑,并进行哈希检查以确定参数是否已更新。在与 List<T>
示例一起工作时,存储哈希字符串比整个列表要便宜得多,这是非常有用的。
OnAfterRender-
:
我通常将此用于 JavaScript。在我使用 Blazor 的大约 4 年中,我只在这里调用 JavaScript。
编辑:
抱歉,我误读了最初的问题,混淆了 SetParametersAsync
与 OnParameterSet-
。
SetParametersAsync
我在早期阶段从未需要使用它。如果您需要使用它,请问自己为什么需要。最好看看如何改进或更改组件以消除这种依赖关系。尽管在组件被渲染成千上万次或具有许多参数时,我可能会在组件上使用它,但再次问一下,为什么要渲染一千次一个组件呢?高参数计数通常告诉我,我的组件需要拆分成多个组件。
在简单组件上(我认为所有组件都应该是简单的),使用 SetParametersAsync
带来的性能提升不值得花费编码时间。另一方面,如果我想尽量提高性能(通常在项目后期),我会开始更新我的组件。但再次强调,你可能只能在大页面上节省 100 毫秒的渲染时间。
Blazor 在这方面非常强大。我看到许多组件库创建了万能组件,而你可以使用包装组件根据需要引入功能。例如,如果你有一个数据表格,可以将筛选器制作成包装器,因为并非所有数据表格都需要筛选器。这对于许多类型的组件都适用,可以大大减少复杂性和提升性能。
英文:
I use the following rule of thumb:
OnInitialized-
:
Here I will get things ready for the component, and very rarely do anything related to component parameters. Very often I will set internal or private parameters/fields for UI based logic or other defaults not set on the parameter/field. Things like rendering of a loading modal, EditContext
etc. If I have a component that does not have parameters, I will add all starting logic here.
OnParameterSet-
:
Here I will add all my component parameter logic and do hash checking to identify whether a parameter updated. Useful when working with your List<T>
example and it's much cheaper storing a hash string instead of a whole list.
OnAfterRender-
:
I usually reserve this for JavaScript. In my ~4 years of Blazor, I've only called JavaScript here.
EDIT:
Apologies, I misread the initial question and confused SetParametersAsync
with OnParameterSet-
.
SetParametersAsync
I've never needed to use this in the early stages. If you need to use this, ask yourself why. Rather see how can you improve or change the component to remove this dependency. Though I would use this on components if they are rendered in the thousands or have a lot of parameters, but then again, why render one component a thousand times? A high parameter count usually tells me that my component needs to be split into multiple components.
On simple components (which I believe all components should be), the performance gain from using SetParametersAsync
is not worth the time to code. On the other hand, if I want to squeeze out as much performance as I can (usually late in the project), I will start updating my components. But then again, you might save 100ms of rendering time on large pages.
Blazor is very powerful in this way. I see many component libraries creating Jack-of-all-trade components when you can use wrapper components that bring in functionality as it's required.
For example, if you have a data table, make your filters a wrapper since not all data tables require filters. This can count for many types of components and saves massively on complexity and performance.
答案3
得分: 2
你的问题提出了组件实现中的一个有趣观点。
如果您正在使用局部变量来跟踪状态,那么您应该考虑在 SetParametersAsync
中设置和跟踪它们,并且不使用自动设置。
这篇微软文章描述了优化组件的策略 - https://learn.microsoft.com/en-us/aspnet/core/blazor/performance?view=aspnetcore-7.0#implement-setparametersasync-manually
这里的重要一点是,在开发时手动编写这段代码可能成本更高,但在执行时更快、更便宜:自动化代码使用反射,这不是快速或便宜的。您只需编写一次代码,但可能会执行数百万次!
我也不同意 @HH 的观点,认为 SetParametersAsync()
难以使用,但这是个人意见。一旦您知道使用的模式,我就不认为有问题。
英文:
Your question brings up an interesting point in Component implementation.
If you are using local variables to track state then you should consider setting and tracking them in SetParametersAsync
and dispensing with the automatic setting.
This MS article describes this strategy to optimize components - https://learn.microsoft.com/en-us/aspnet/core/blazor/performance?view=aspnetcore-7.0#implement-setparametersasync-manually
The important point here is it may be more costly in dev time to code this manually, but in execution time it's quicker and less expensive: the automated code uses reflection which isn't quick or cheap. You only code it once, but is could get executed millions of times!
I also beg to differ with @HH on SetParametersAsync() is pretty tricky to use
, but that's a personal opinion. Once you know the pattern to use, I don't see an issue.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论