getStores().page.subscribe() VS page.subscribe() - what's the difference?

Viewed 238

I can't for the life of me understand when it is necessary to use getStores, and what happens if I use for example page.subscribe() instead of getStores().page.subscribe()?

Can someone provide an example of when page.subscribe() goes wrong, and WHAT goes wrong?

The documentation says that using getStores() is "safely" - I have no idea what that means. Documentation - https://kit.svelte.dev/docs/modules#$app-stores

1 Answers

Rich Harris wrote back - https://github.com/sveltejs/kit/issues/4078#issuecomment-1048912732

When you import page, you're not actually importing the page store. That would be impossible, because the stores aren't free-floating objects, they're scoped to your app using Svelte context (if they weren't, on the server they would be shared by everyone who makes a request).

Instead, you're importing this:

https://github.com/sveltejs/kit/blob/88ebc8e3033496cd842cf29fa127f5d7efc3d184/packages/kit/src/runtime/app/stores.js#L40-L47

getStores uses context to retrieve the actual app-scoped stores:

https://github.com/sveltejs/kit/blob/88ebc8e3033496cd842cf29fa127f5d7efc3d184/packages/kit/src/runtime/app/stores.js#L17-L18

But you can only call getContext during a component's initialisation. Most of the time that's fine, because if you do something like this...

<script>
  import { page } from '$app/stores';
</script>

<h1>{$page.url.pathname}</h1>

...Svelte is calling page.subscribe on your behalf (which in turn calls getStores, which in turn calls getContext) during init. But if you tried to subscribe later for some contrived reason...

<script>
  import { page } from '$app/stores';

  let pathname = 'untracked';

  function start_subscribing() {
    page.subscribe($page => {
      pathname = $page.url.pathname;
    });
  }
</script>

...then you'd be calling getContext outside component init, which would fail. If you instead use getStores...

<script>
  import { getStores } from '$app/stores';

  const { page } = getStores();

  let pathname = 'untracked';

  function start_subscribing() {
    page.subscribe($page => {
      pathname = $page.url.pathname;
    });
  }
</script>

...you can subscribe safely.

Related