ljbc1994 / BlazorIntersectionObserver

🔎 Intersection Observer API wrapper for Blazor applications
MIT License
61 stars 12 forks source link

Delay JSInterop until after prerender #18

Closed TLabWest closed 3 years ago

TLabWest commented 3 years ago

In a Blazor-Server setup I get the following error during startup:

System.InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.
         at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson, JSCallResultType resultType, Int64 targetInstanceId)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, CancellationToken cancellationToken, Object[] args)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
         at Blazor.IntersectionObserver.IntersectionObserverService.DisposeAsync()
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.<DisposeAsync>g__Await|15_0(Int32 i, ValueTask vt, List'1 toDispose)
         at Microsoft.AspNetCore.Http.Features.RequestServicesFeature.<DisposeAsync>g__Awaited|9_0(RequestServicesFeature servicesFeature, ValueTask vt)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<FireOnCompleted>g__ProcessEvents|227_0(HttpProtocol protocol, Stack'1 events)

To reproduce the error, simply add the <IntersectionObserve> component to a Blazor (.razor) component and launch the Blazor Server app. Unfortunately I don't have a small repro project right now, I could get back to you with one should it still be needed.

NB: It still works, it's just flooding my error log with unsightly call stacks. I have worked around the problem by flagging a bool in my own OnAfterRenderAsync() and only including the <IntersectionObserve> component conditionally when that flag is set. Still, this should probably be handled more centrally in the IntersectionObserve component itself.

More information and simple examples can be found here: https://docs.microsoft.com/en-us/aspnet/core/blazor/call-javascript-from-dotnet?view=aspnetcore-5.0#detect-when-a-blazor-server-app-is-prerendering

ljbc1994 commented 3 years ago

Hi @TLabWest,

Thanks for raising this, I can replicate but I think it's to do with the initial import of the observer js which occurs when the service is initialised.

The <IntersectionObserve> component does check to initialise the observer after render:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await this.InitialiseObserver();
    }
}

Will be looking into this and let you know when it's been fixed.

Thanks!

ljbc1994 commented 3 years ago

This is fixed in the latest release #23, however it does contain a breaking change in relation to the component so please be aware of that!