Exposing child component state in Svelte

There are a few different ways to expose child component state to parent components in Svelte, each of them have their benefits and drawbacks.

Events

The first possibility is to emit an event that the parent can subscribe to every time the child’s relevant state changes.

Foo.svelte:

<script>
  import {onMount, createEventDispatcher} from 'svelte';
  export let $foo = 0;

  const dispatch = createEventDispatcher();

  onMount(() => {
   const t = setTimeout(() => {
     foo++;
     dispatch("fooupdate", foo)
   }, 100);
   return (() => {
     clearTimeout(t)
   });
  });
</script>

App.svelte:

<script>
  import Foo from './Foo.svelte';
  let foo;
</script>

<Foo on:fooupdate={(newVal) => (foo = newVal)} /><h1>{foo}</h1>

Stores

It’s also possible to export a const by wrapping it in some kind of mutable structure. Svelte’s stores work well for this. Either a writable or derived store could be used. A writable store will allow the value to be set from outside the component and a derived store results in a read-only exported state value.

Foo.svelte:

<script>
  import {onMount} from 'svelte';
  import { writable } from 'svelte/store';

  export const foo = writable(0);

  onMount(() => {
   const t = setTimeout(() => {
     $foo++;
   }, 100);
   return (() => {
     clearTimeout(t)
   });
  });
</script>

App.svelte:

<script>
  import Foo from './Foo.svelte';
  let foo;
</script>

<Foo bind:foo /><h1>{$foo}</h1>

Two-way bindings

This has the possible disadvantage that it’s then possible to set (or re-set) child state from the parent component. This would be potentially confusing or bug-prone if the child state is intended to be entirely controlled by the child component.

Foo.svelte:

<script>
  import {onMount} from 'svelte';
  export let foo = 0;

  onMount(() => {
   const t = setTimeout(() => {
     foo++;
   }, 100);
   return (() => {
     clearTimeout(t)
   });
  });
</script>

App.svelte:

<script>
  import Foo from './Foo.svelte';
  let foo;
</script>

<Foo bind:foo /><h1>{foo}</h1>

Read only props request/proposal

There is an issue that proposes a method be established to enable read-only bindings. This would be a welcome addition.

code-libraryjavascript