sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.19k stars 4.09k forks source link

Svelte throws exception due to apparent race condition when a component sets a store when first loading #7458

Closed dimfeld closed 5 months ago

dimfeld commented 2 years ago

Describe the bug

In some cases, a component that immediately modifies a store when loading (or in onMount apparently) can cause exceptions in other components that use that store if they haven't finished mounting yet.

From what I've been able to figure out, the timeline is something like this:

  1. A component loads that uses the store
  2. Another component loads that writes the store when it starts
  3. Writing the store causes the first component to be marked dirty even though the component hasn't actually mounted yet.
  4. A third component loads and calls flush at the end of its init function.
  5. flush goes through and calls update on all the dirty components, which in turn calls $$.fragment.p. But since the first component hasn't actually mounted yet, it's dealing with elements that either don't exist or are not yet added to the DOM and so these may throw exceptions.

I'm not entirely sure if using the client component API is necessary to make this happen. It is necessary in my reproduction, and I'm using it in my real SvelteKit project as well where I first encountered this bug, but in a very different place so I'm not entirely sure.

This can be worked around by waiting a tick to set the store:

let destroyed = false;
onDestroy(() => (destroyed = true));
tick().then(() => {
  if (!destroyed) {
    $s = true;
  }
});

This workaround succeeds in both my reproduction here and in my actual much more complicated app.

It feels like the proper fix is not set ready in the component until it has actually finished mounting, but I'm kind of guessing here and am not sure if that might mess up something else.

Reproduction

REPL: https://svelte.dev/repl/1d363ab12dc84315a38472e29f5b2ed3?version=3.47.0 SvelteKit: https://github.com/dimfeld/svelte-update-bug

The code is pretty much the same in the above two.

Logs

No response

System Info

Svelte REPL

Severity

annoyance

Rich-Harris commented 5 months ago

Looks like whatever this was, it's fixed in Svelte 5, so I'll close this