Search code examples
videohtml5-videosveltesvelte-componentsvelte-3

Svelte: Remount component to overwrite media elements


  • Context

In my Svelte app, I have multiple pages, each showing one or multiple videos. For rendering the videos I reuse a video component (simplified):

// video component
<video poster="{source.thumb}">
    <source type="{source.mime}" src="{source.source}" >
</video>

The main page receives the video content via an api and calls the video component:

// calling video component on main page
<script>
    let source = {
        thumb: 'thumb.jpg',
        source: 'video.mp4',
        mime: 'video/mp4',
    };
</script>
<Video source={source} />

All works fine, the video is rendered and can be played.

  • Problem

But: when I navigate or want to replace a video with another, the old video element somehow still exists and playback continues.

I could use beforeUpdate() to pause the video. But then, the new video weirdly is loaded at the exact same playback time and everything gets mixed up. Or if I remove the video element in beforeUpdate(), it doesn't get filled with the new information.

It kinda makes sense, because the video media element stays the exact same thing while only attributes and content change. Thus the state and already buffered source remains.

I somehow would need to assure, that when the data changes, the video component must completely be remounted. Does anyone know how to do that? Thanks!


Solution

  • After some trial and error and with the help of @voscausa it now works:

    <script>
        export let source;
    
        let renderVideo = true;
    
        $: { reMountVideo( source.source ) }
        function reMountVideo(){
            renderVideo = false;
            setTimeout(() => renderVideo = true, 0);
        }
    </script>
    {#if renderVideo === true}
        <video poster="{source.thumb}">
            <source type="{source.mime}" src="{source.source}" >
        </video>
    {/if}
    

    It checks if the video url changes, and if so, triggers reMountVideo().