DEV Community

Bigi Lui
Bigi Lui

Posted on • Updated on • Originally published at bigi.dev

Svelte/Sapper Issue with Switching Components

I ran into what might be my first Svelte bug when working on the Big2 card game project. Very roughly, I have a page setup that looks like this (<script> and <style> sections omitted, and unrelated component properties omitted):

<main>
  {#if $state === 'game'}
    <GameStageLocal />
  {:else if $state === 'deal'}
    <DealAnimation onDone={dealingDone} />
  {:else}
    <div>Initializing...</div>
  {/if}
</main>
Enter fullscreen mode Exit fullscreen mode

The <DealAnimation> component plays some game start animation and when it's done, it calls the onDone handler passed into it. What it will do is to update state (a Writable Store) to game so the interactive game UI will start.

As you can deduce from the code above, $state is an auto-subscribed store so when its value changes, it would change the DOM on the page such that <GameStageLocal> is now what's on the page, and <DealAnimation> would be removed from the DOM.

When testing it, the Firefox console gave the following error:

TypeError: t.parentNode is null
Enter fullscreen mode Exit fullscreen mode

It was a bit baffling since I couldn't really find an error in my Svelte code and there wasn't any error in the Svelte dev build output. Upon searching online, I came across this StackOverflow post which has exactly my issue. Although the answer mentions that:

Ran into this error recently. In my case it was due to another library changing the DOM. (In my case fontawesome)

I was not using another library to change the DOM; only Svelte. Either way, though, the described fix in the answer worked for me, which was to wrap my components inside those conditions in another node, like below:

<main>
  {#if $state === 'game'}
    <div>
      <GameStageLocal />
    </div>
  {:else if $state === 'deal'}
    <div>
      <DealAnimation onDone={dealingDone} />
    </div>
  {:else}
    <div>Initializing...</div>
  {/if}
</main>
Enter fullscreen mode Exit fullscreen mode

And this worked fine.

Parting Thoughts

I think this does go to show the relative immaturity of Svelte in general, compared to React or Vue. I remain a fan of Svelte, but nevertheless it's good to keep in mind that when you use a small framework, you're bound to run into actual bugs in the framework.

Top comments (3)

Collapse
 
mikenikles profile image
Mike

Thanks for sharing that.

Remember, React didn't have fragments for the longest time and required you to return a single parent element for each component. I don't know the details of the Svelte bug, but worth keeping in mind that any new code base such as Svelte comes with some rough edges.

Collapse
 
bigi profile image
Bigi Lui

I didn't know that part about React and the way you described the problem makes sense that it's a difficult thing to tackle (removing a component that doesn't have a single wrapper element around it) when it comes to DOM manipulation. Thanks!

Collapse
 
torstendittmann profile image
Torsten Dittmann • Edited

This is not about the immaturity of Svelte, but more about the immaturity of Sapper.

Sapper does not seem to get that much love and is still in a relatively useless condition in my opinion.