javascriptblazorblazor-webassemblyrive

Blazor WASM - JS(rive app) is not being re-rendered after default navigating


I have issue with re-rendering rive animation after I leave default page "/". When I return back (/counter -> /) animation is not displayed anymore but js modul is being called in the code so I am not sure how can I deal with this problem.

here is a code:

Index.razor->

@page "/"
@inject IJSRuntime JSRuntime

<canvas id="canvas" width="500" height="500"></canvas>

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./Pages/Index.razor.js");
        }
    }
}

Index.razor.js ->

const r = new rive.Rive({
    src: 'bear.riv',
    canvas: document.getElementById('canvas'),
    autoplay: true,
    })

Index.html ->

    <script src="_framework/blazor.webassembly.js"></script>
    <script src="https://unpkg.com/@rive-app/canvas@1.0.79"></script>

Any advice would be much appreciated. Thank you!


Solution

  • The problem is that that "import" will only happen once and your animation will keep running (I think) against the old canvas. That means you probably have a memory leak too.

    A solution would look like this:

    @implements IAsyncDisposable
    ...
    IJSObjectReference? rivWrapper;
    
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {                        
            rivWrapper = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./Pages/Index.razor.js");
            await rivWrapper.InvokeVoidAsync("createRive");         
        }
    }
    
    public async ValueTask DisposeAsync()
    {
        await rivWrapper!.DisposeAsync();
    }
    
    

    and the JS

    export function createRive() {        
        const r = new rive.Rive({
            src: 'bear.riv',
            canvas: document.getElementById('canvas'),
            autoplay: true,
        });
    }
    

    Note that I'm very weak on Javascript, this might still leak. See this for further reference about adding a dispose().