With Blazor WebAssembly WASM, everything is about components. It means that each component load his content (nearly) independently form other components. Therefore when navigation occurs and the new active page loads some parts of the DOM are displayed before others. For example the header and the footer are probably loading quicker than the main container in which some fetching occurs (API calls). This has the (side) effect that at one point we can see the header and the footer one below the other (as glued) and 2 seconds after seeing the main container injected between the two. I am thinking of a solution to get around this problem. I would like that during page loading nothing is visible until everything is in place (binding + images loaded, etc...).
You will understand that i am not talking about the initial (big) load of blazor but rather the transition between pages.
For example, below is my MainLayout.razor
<div class="container page">
<HeaderSection />
@Body
<NewsLetterSection />
<FooterSection />
</div>
As you know, each (blazor) pages are injected in the @Body.
Example of page is Todo.razor
@page "/todo"
@if (todolist != null)
{
foreach (var todo in todolist)
{
@todo.task
}
}
If user navigate to another (blazor) page of the site, at first page should be totally blank (header, main container, footer, ...) until everything is 'ready' to make the page visible again (with everything in place) and appearing without the blinking effect.
I know there are some solutions made available by some people but these does not fit my needs because these solutions mainly concentrate the effort on the page itself and not the entire layout. As explained, when page transition occurs, I would like everything in my MainLayout.razor to be masked until everything is in place on the destination page.
I already try something like explained on the accepted answer here: Call method in MainLayout from a page component in Blazor but not succeed.
I know when navigation occurrs: on NavigationManager.LocationChanged event but I cannot detect when everything is in place on the page. It would have been beneficial to have Task OnAfterRenderAsync(bool firstRender, bool lastRender).
Any idea to put me on the right track ?
UPDATE 1
I came up to a solution based on a State Container. For more info see point 3 here
VisibilityStateContainer.cs
public class VisibilityStateContainer
{
public bool IsVisible { get; private set; }
public event Action OnChange;
public void SetVisibility(bool value)
{
IsVisible = value;
NotifyStateHasChanged();
}
private void NotifyStateHasChanged() => OnChange?.Invoke();
}
Below code of the component who fetch data
@implements IDisposable
@inject VisibilityStateContainer VisibilityStateContainer
@code
{
protected override async Task OnInitializedAsync()
{
VisibilityStateContainer.OnChange += StateHasChanged;
VisibilityStateContainer.SetVisibility(false);
SomeData = await MyService.GetData();
VisibilityStateContainer.SetVisibility(true);
}
public void Dispose()
{
VisibilityStateContainer.OnChange -= StateHasChanged;
}
}
@if (VisibilityStateContainer.IsVisible)
{
<div>
...
</div>
}
Below code of any other component
@implements IDisposable
@inject VisibilityStateContainer VisibilityStateContainer
@code
{
protected override async Task OnInitializedAsync()
{
VisibilityStateContainer.OnChange += StateHasChanged;
}
public void Dispose()
{
VisibilityStateContainer.OnChange -= StateHasChanged;
}
}
@if (VisibilityStateContainer.IsVisible)
{
<div>
...
</div>
}
This basic solution works when there is only one (main) component which load data asynchronously while others just 'listen' for the OnChange state. Everytime navigation occurs, everything is hided at first until IsVisible flag is set (by the component who fetch data). Only then all components are displayed at the same time. If multiple components may load data asynchronously (and thus takes time to render) then the State Container should be modified to take this into account not simply with a boolean IsVisible but maybe an array of boolean.
UPDATE 2 - visual representation of the problem
When you navigate from page A to page B, multiple components (on the page) should be displayed. Data need to be loaded (fetch API) in the initialization event of the main component (green colored). While data is fetched, we can display a spinner or loading message like below in this component. Meanwhile we can already see other Blazor components below.
When data is loaded successfully (see below), the loading message disappear and the page is showing all the content consequently pushing newsletter and footer lower on the page. The side effect of this is a kind of ugly effect (at my point of view).
I agree this is frequent to see pages building in multiple refreshing steps. This is not specific to blazor! When navigation occurs, personnally I prefer to hide everything (except the header) until the page can be displayed in 1 unique refresh. Hope this gives you a better understanding of the problem.
So I suggest a solution in my update 1 (see above). It fit my needs but please let me know if there are better alternative.


My preferred solution is to add a div with a loading indicator, which is shown while the data is being fetched, on the individual pages themselves. This div, with appropriate css, acts as a placeholder that keeps the layout from jumping when the content is ready.
It's also better UX to navigate to the new page immediately based on a user action and then indicate that the data is loading. A progress bar would be the best option if the data takes more than a a couple of seconds, but often it is good enough to show a wait spinner or a "Loading..." text as below.