Svelte and SvelteKit course · Module 8: Stores

Readable and Derived Stores

2 min read ·
In this lesson3

Readable Store

A read-only store - set externally:

import { readable } from 'svelte/store';

// Current time
export const time = readable(new Date(), function start(set) {
  const interval = setInterval(() => {
    set(new Date());
  }, 1000);

  // Cleanup - when the last subscriber leaves
  return function stop() {
    clearInterval(interval);
  };
});

// Mouse position
export const mousePosition = readable({ x: 0, y: 0 }, set => {
  function handler(e) {
    set({ x: e.clientX, y: e.clientY });
  }

  window.addEventListener('mousemove', handler);

  return () => {
    window.removeEventListener('mousemove', handler);
  };
});

Derived Store

Computed from other stores:

import { writable, derived } from 'svelte/store';

export const warriors = writable([
  { name: 'Ragnar', strength: 95 },
  { name: 'Bjorn', strength: 88 }
]);

// Single dependency
export const totalStrength = derived(
  warriors,
  $warriors => $warriors.reduce((sum, w) => sum + w.strength, 0)
);

// Multiple dependencies
export const gold = writable(100);
export const items = writable(5);

export const canBuy = derived(
  [gold, items],
  ([$gold, $items]) => $gold >= 50 && $items < 10
);

Async Derived

export const asyncData = derived(
  userId,
  ($userId, set) => {
    set(null); // Loading state

    fetch(`/api/user/${$userId}`)
      .then(r => r.json())
      .then(data => set(data));

    // Optional cleanup
    return () => {};
  },
  null // Initial value
);
Code for this lesson: App.svelte
<script>
  // readable store - read-only
  import { time, elapsed } from './stores.js';
</script>

<main class="time-demo">
  <h1>⏰ readable store</h1>
  <p class="subtitle">Read-only store</p>

  <section>
    <h2>Current time</h2>
    <div class="clock">{$time.toLocaleTimeString()}</div>
  </section>

  <section>
    <h2>Time since load</h2>
    <div class="elapsed">{$elapsed}s</div>
  </section>

  <section class="code">
    <h2>How does it work?</h2>
    <pre>
import {"{"} readable {"}"} from 'svelte/store';

export const time = readable(new Date(), set => {"{"}
  const interval = setInterval(() => {"{"}
    set(new Date());
  {"}"}, 1000);

  // Cleanup
  return () => clearInterval(interval);
{"}"});
    </pre>
  </section>
</main>

<style>
  .time-demo {
    font-family: 'Georgia', serif;
    max-width: 500px;
    margin: 0 auto;
    padding: 2rem;
    background: #0a1628;
    color: #b8d4f7;
    min-height: 100vh;
  }

  h1 {
    color: #4a90d9;
    text-align: center;
  }

  .subtitle {
    text-align: center;
    color: #6a8ab9;
  }

  section {
    background: rgba(74, 144, 217, 0.1);
    border: 1px solid #4a90d9;
    border-radius: 8px;
    padding: 1rem;
    margin: 1rem 0;
  }

  h2 {
    color: #4a90d9;
    font-size: 1rem;
    margin-top: 0;
  }

  .clock {
    font-size: 3rem;
    font-family: monospace;
    text-align: center;
    color: #7cb3f0;
  }

  .elapsed {
    font-size: 2rem;
    font-family: monospace;
    text-align: center;
    color: #90ee90;
  }

  .code pre {
    background: rgba(0,0,0,0.5);
    padding: 1rem;
    border-radius: 4px;
    font-size: 0.85rem;
    overflow-x: auto;
  }
</style>

Docs entries used in this lesson

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. How does a readable store differ from a writable store?

Useful articles