Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Way to detect pre-rendering in Server-side Blazor #17282

Closed
Grauenwolf opened this issue Nov 21, 2019 · 5 comments
Closed

Way to detect pre-rendering in Server-side Blazor #17282

Grauenwolf opened this issue Nov 21, 2019 · 5 comments
Labels
area-blazor Includes: Blazor, Razor Components

Comments

@Grauenwolf
Copy link

Is your feature request related to a problem?

When I am rendering the landing page of my application, there are two modes.

Mode 1 occurs during prerendering. This is stuff that I would like your typical search engine to index.

Mode 2 occurs after the connection is established. It contains all of the information from mode 1 plus additional information from the browser's local storage. (Essentially preferences they selected. We use local storage because this application doesn't support authentication.)

Describe the solution you'd like

I would like a simple property on ComponentBase that indicates whether I'm pre-rendering or connected. This way I can know whether or not to attempt to read from browser local storage and otherwise interact with JavaScript.

Additional context

It is my understanding that this was previously offered in the beta version of server-side blazor.

Currently I use a work-around where I have to try to execute a dummy JavaScript method. However, this work-around has numerous problems including causing the IDE to break when the exception is thrown.

        //Razor Component

        protected bool IsConnected { get; set; }

        protected async override sealed Task OnInitializedAsync()
        {
            await base.OnInitializedAsync();
            try
            {
                var result = await JSRuntime.InvokeAsync<bool>("isPreRendering");
                IsConnected = true;
            }
            catch (NullReferenceException)
            {
            }
        }
    //_Host.cshtml

    isPreRendering = () => {
        return false;
    };
@pranavkm pranavkm added the area-blazor Includes: Blazor, Razor Components label Nov 21, 2019
@javiercn
Copy link
Member

javiercn commented Nov 21, 2019

@Grauenwolf thanks for contacting us.

We don't recommend you perform any JS interop within OnAfterRender calls, as that's the time where the browser is connected to the client. If you want to do this yourself, you can achieve it by creating and registering your own service in DI.

public class RenderingContext
{
  public bool IsPrerendering { get; set; } = false;
}

Resolve it on your host, set it to true before you prerender and then set it to false after that.
You can then create your own base component, inject this service on it and reuse it across all your components.

Hope that helps.

@Grauenwolf
Copy link
Author

Grauenwolf commented Nov 21, 2019

We don't recommend you perform any JS interop within OnAfterRender calls

That doesn't make any sense. Your documentation literally says to do it in the section titled "Detect when a Blazor app is prerendering".

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender && infoFromJs == null)
    {
        infoFromJs = await JSRuntime.InvokeAsync<string>(
            "setElementText", divElement, "Hello from interop call!");

        StateHasChanged();
    }
}

https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interop?view=aspnetcore-3.0#detect-when-a-blazor-app-is-prerendering

However, this documentation hides a problem. Because you won't provide us a simple flag, we have to do render the page 3 times.

  1. pre-rendering
  2. normal rendering prior to detecting the connection
  3. rendering again after performing any necessary JS interopt

Can you at least tell us why you won't even consider it?

@Grauenwolf
Copy link
Author

Resolve it on your host, set it to true before you prerender and then set it to false after that.

And how do I know if I'm pre-rendering? The whole problem is that I don't know until OnAfterRenderAsync is called, by which point it's too late. I've already rendered, so I can't get the information I need from Local Storage to render.

Again, I've have to ether go through another entire round of rendering or do the ugly hack with JSInteropt throwing an exception.

@sprotty
Copy link

sprotty commented Dec 7, 2019

Did you ever figure out a good way to detect the pre-render (ideally in OnInitialized/OnInitializedAsync), or is the code above as good as it gets?

I've got a control that takes a while to load data in OnInitializedAsync, the result being that nothing is rendering to the client until its completed the whole pre-render, so its unresponsive while its doing all the work the first time, then has to do all the work again for the real render....

I can't see why a flag to detect this is not provided.

@Grauenwolf
Copy link
Author

Nope, they just keep blindly closing tickets without explanation.

So I'm still using the annoying "just catch the exception" style. It's rather unprofessional but what choice do we have?

@ghost ghost locked as resolved and limited conversation to collaborators Jan 6, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

No branches or pull requests

4 participants