C
C#7mo ago
SaschaXVII

.NET 8, Blazor InteractiveServer with StreamRendering causing double rendering

Hi, I was trying out the new features added to Blazor in .NET 8, but have to admit that I don't know much about Blazor in the first place. I mainly use MVC, React and Angular, but wanted to get into Blazor a bit more. Now, I love the Stream Rendering and Interactive Server via a websocket connection stuff I've seen so far, but when I tried to test those two things combined in one component, I noticed that it leads to the component being rendered twice, once because of server pre-rending (i suppose), and then again after. This happens only when both Interactive Server and Stream Rendering is enabled. I added an artificial delay for my data to load to make this obvious, and a loading spinner. If you run the following code, you will notice that the component loads, the spinner starts spinner, then you see the data for a fraction of a second, and then it goes back to the spinner for another loading circle. Now I am looking for a fix as much as suggestions for what the best practice in general would be for a simple component that is interactive, but also relies on fetched data initially? I don't have access to my code right this second, but it looked something like this:
@page "/todo"
@rendermode InteractiveServer
@attribute StreamRendering
if (todos == null)
{
<p>Loading...</p>
}
else
{
<ul>
@foreach (var todo in todos)
{
<li>@todo.Title</li>
}
</ul>
}

@code {
private List<TodoItem>? todos;

protected override async Task OnInitializedAsync()
{
await Task.Delay(1000);
// love the new collection expressions btw!!
todos = [ new TodoItem(), new TodoItem(), new TodoItem() ];
}
}
@page "/todo"
@rendermode InteractiveServer
@attribute StreamRendering
if (todos == null)
{
<p>Loading...</p>
}
else
{
<ul>
@foreach (var todo in todos)
{
<li>@todo.Title</li>
}
</ul>
}

@code {
private List<TodoItem>? todos;

protected override async Task OnInitializedAsync()
{
await Task.Delay(1000);
// love the new collection expressions btw!!
todos = [ new TodoItem(), new TodoItem(), new TodoItem() ];
}
}
1 Reply
carbontsunami
carbontsunami7mo ago
to prevent from double rendering there is a way to do. You can move your loading code from OnInitializedAsync to OnAfterRenderAsync private List<TodoItem>? todos; protected override async Task OnInitializedAsync() { // } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await Task.Delay(1000); // love the new collection expressions btw!! todos = [new TodoItem(), new TodoItem(), new TodoItem()]; StateHasChanged(); } }