search

Home  >  Q&A  >  body text

Passing objects as props in Svelte keeps object fields in HTML from changing?

I have this Svelte code:

Player.svelte:

<script>
    import PlayerControls from './PlayerControls.svelte';

    let audio;
</script>

<audio src={...} bind:this={audio} />
<PlayerControls {audio} />

PlayerControls.svelte:

<script>
    import PlayIcon from '../icons/PlayIcon.svelte';
    import PauseIcon from '../icons/PauseIcon.svelte';

    export let audio;

    const onClick = () => {
        if (audio?.paused) audio.play();
        else audio.pause();
    };
</script>

{#if audio?.paused}
    <PlayIcon {onClick} />
{:else}
    <PauseIcon {onClick} />
{/if}

If I press the play icon, the icon does not change, but the audio starts, if I click again, the audio stops, but the icon does not change. It seems that audio.paused only "changes" in the script, not in the html. What's the problem here, and what don't I understand about Svelte?

P粉550823577P粉550823577243 days ago345

reply all(1)I'll reply

  • P粉546179835

    P粉5461798352024-03-28 21:25:26

    In your given case, the most robust solution is to utilize specific <audio> elements Events to alert svelte to recheck the status of the ref. This allows svelte to manage your listener lifecycle, and also allows the element itself to handle all edge cases of when/how the playback state changes.

    sssccc
    
    

    REPL

    Original answer

    The documentation link in my comment covers a simple solution to your problem Reactivity/Updating Arrays and Objects, which is to simply reassign audio as onClick The last step in the handler.

    Keep in mind that this will not track changes in paused if the audio ends on its own.

    const onClick = () => {
        if (audio?.paused) audio.play();
        else audio.pause();
        
        audio = audio;
    };

    REPL

    edit

    I initially suggested changing the paused attribute directly:

    const onClick = () => {
      if (audio?.paused) {
        audio.play();
        audio.paused = false;
      } else {
        audio.pause();
        audio.paused = true;
      }
    };

    But ignores the fact that audio is a ref and paused is a read-only property.

    reply
    0
  • Cancelreply