nstuyvesant
nstuyvesant

Reputation: 1516

How to keep a readable store in SvelteKit from being unsubscribed when changing pages/routes

In SvelteKit, I get "Subscribed" and "Unsubscribed" logged to the console each time I navigate between the /first and /second routes. I want to have the readable's start function run only once for each user who visits the website - allowing me to store fetched data that doesn't change often.

// stores.ts
import { readable } from 'svelte/store'
const { VITE_WEB_URL } = import.meta.env

export const message = readable('', set => {
  console.log('Subscribed')
  const fetchMessage = async () => {
    const url = `${VITE_WEB_URL}/api/message`
    const response: Response = await fetch(url)
    return await response.text()
  }
  fetchMessage()
    .then(set)
    .catch(err => console.error('Failed to get message', err))
  return () => {
    console.log('Unsubscribed')
  }
})
<!-- /routes/first.svelte -->
<script>
    import { message } from '../stores'
</script>

<h1>First: {$message}</h1>

<a href="/second">Second</a>
<!-- /routes/second.svelte -->
<script>
    import { message } from '../stores'
</script>

<h1>Second: {$message}</h1>

<a href="/first">First</a>

As I navigate between pages/routes in SvelteKit, unsubscribe is called so the next page/route invokes the start function as the "first" subscriber.

How can readable stores be shared across multiple pages/routes without re-running the start function? I've heard suggestions about using the template but have never seen an example.

Would the template get the store value and pass it as props to components or simply prevent the store from having a "last subscriber" (effectively keep the door open)?

Upvotes: 4

Views: 2860

Answers (2)

nstuyvesant
nstuyvesant

Reputation: 1516

If you are using a template, the readable store can stay subscribed in a number of ways so as to not re-invoke the start function:

  1. Referencing $message directly in __layout.svelte either in the script or template
  2. Loading other Svelte components that directly reference $message or that contain Svelte components that do.
<!-- /lib/ComponentUsingMessage.svelte-->
<script>
  import { message } from '../stores'
</script>

<p>{$message}</p>
<!-- /routes/__layout.svelte-->
<script>
  import { message } from '../stores'
  // Or include a component in the template that loads $message...
  import ComponentUsingMessage from '$lib/ComponentUsingMessage.svelte'
</script>

<main>
  Both subscribe but do not unsubscribe while template is loaded:
  {$message}
  <ComponentUsingMessage/>

  <slot></slot>
</main>

Upvotes: 2

Zachiah
Zachiah

Reputation: 2627

It says that it is called when the first subscriber subscribes and then the delete function is called when the last subscriber unsubscribes. When you change routes it unsubscribes all subscribers and then runs the delete function, then when you get to the next route it reruns the initial function.

Upvotes: 1

Related Questions