Skip to content

Instantly share code, notes, and snippets.

@shirakaba
Last active May 6, 2021 20:12
Show Gist options
  • Save shirakaba/4bc215a904bc9a04a35b0618d50ddf10 to your computer and use it in GitHub Desktop.
Save shirakaba/4bc215a904bc9a04a35b0618d50ddf10 to your computer and use it in GitHub Desktop.
Svelte custom store example
import { writable, derived } from 'svelte/store';
function createCountries() {
const { subscribe, update } = writable([
{
name: "United Kingdom",
weather: "Cold",
description: "Nice tea",
},
{
name: "France",
weather: "Warm",
description: "Good access to the United Kingdom",
}
])
function add(country) {
update(items => [...items, country])
}
return {
subscribe,
add,
}
}
export const countries = createCountries();
export const selectedCountryName = writable('');
export const country = derived(
[countries, selectedCountryName],
([$countries, selectedCountryName]) => $countries.find(c => c.name === selectedCountryName)
);
@shirakaba
Copy link
Author

From trying to improve upon:

<script>
  let navigationStack = [{
    template: "list_of_items",
    title: "Country List",
    items: [
      {
        template: "country_detail",
        name: "United Kingdom",
        weather: "Cold",
        description: "Nice tea",
      },
      {
        template: "country_detail",
        name: "France",
        weather: "Warm",
        description: "Good access to the United Kingdom",
      },
      // ... etc.
    ],
  }];


  $: topCard = navigationStack[navigationStack.length - 1];

  function goToDetail(item){
    /* Problem: the UI doesn't re-render, because topCard doesn't update. */
    // navigationStack.push(item);

    /* Problem: A bit cumbersome to deep-clone all the right parts of heavily-nested structures. */
    navigationStack = [...navigationStack, item];
    console.log(`navigationStack updated to:`, navigationStack);
  }
  function updateWeather(card){
    /* Problem: the UI doesn't re-render, because topCard doesn't update. */
    // card.weather = card.weather + "er";

    /* Problem: Cumbersome to write, and only happens to show consistent data in the Country List because we pushed a shallow clone. */
    // navigationStack[navigationStack.length - 1].weather = navigationStack[navigationStack.length - 1].weather + "er";

    /* Problem: Deep cloning the whole structure is very cumbersome indeed. */
    const newWeather = card.weather + "er";
    navigationStack = [
        {
            ...navigationStack[0],
            items: navigationStack[0].items.map(item => {
                if(item.name !== card.name){
                    return item;
                }
                return {
                    ...item,
                    weather: newWeather,
                }
            }),
        },
        {
            ...navigationStack[navigationStack.length - 1],
            weather: newWeather,
        },
    ];
    console.log(`navigationStack updated to:`, navigationStack);
  }
  function goBack(){
    /* Problem: the UI doesn't re-render, because topCard doesn't update. */
    // navigationStack.pop();

    /* Problem: A bit cumbersome to deep-clone all the right parts of heavily-nested structures. */
    navigationStack = [...navigationStack.slice(0, -1)];
    console.log(`navigationStack updated to:`, navigationStack);
  }
</script>

{#if topCard}
  <fieldset>
    {#if topCard.template === "list_of_items"}
        <legend>{topCard.title}</legend>
        <ul>
          {#each topCard.items as item}
            <li><button on:click={(event) => goToDetail(item)}>{item.name} ({item.weather})</button></li>
          {/each}
        </ul>
    {:else if topCard.template === "country_detail"}
        <legend>{topCard.name}</legend>
        <section style="text-align: center;">
            <p><strong>Description:</strong> {topCard.description}</p>
            <p><strong>Weather:</strong> {topCard.weather}</p>
            <button on:click={(event) => updateWeather(topCard)}>Update weather</button>
            <button on:click={(event) => goBack()}>Go back</button>
        </section>
    {/if}
  </fieldset>
{/if}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment