Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make AJAX Request from Store

I have 3 questions regarding Svelte Stores:

  1. How do I make ajax request inside a store? I've tried using the following:

REPL Demo

//store.js

import { writable } from 'svelte/store';

let data = [];

const apiURL = "https://jsonplaceholder.typicode.com/todos";

async function getData(){
    const response = await fetch(apiURL);
    data = (await response.json()).slice(0,20);
    console.log('Response:', data);
}
getData();

export const testsStore = writable(data);

The request goes trough but the data never gets passed to the export. All the examples I've seen use static data without async/await. I've also tried return data; and writable(getData()); but it return a promise and not the data itself.

  1. Is this even the right way of loading data from API into a store or should I make the call somewhere else.

  2. How and when do I use export default testsStore; I tried using it from another example and it throws saying that store.js isn't exporting testsStore

like image 923
Miro Avatar asked Nov 12 '20 06:11

Miro


Video Answer


1 Answers

Since it's a writable store, you can call set or update on it to change the data (see docs).

For example:

import { writable } from 'svelte/store';

const apiURL = "https://jsonplaceholder.typicode.com/todos";

async function getData(){
    const response = await fetch(apiURL);
    const data = (await response.json()).slice(0,20);
      testStore.set(data) // <================================
}
getData();

export const testStore = writable([])

However, it seems that this specific use case would be better served by a readable store. A readable store takes its initial value as first argument and a "lifecycle" function as its second argument. The lifecyle function receives a set function to change the store value, but the store itself doesn't expose set or update methods (hence it's not writable from the outside).

For example:

import { readable } from 'svelte/store';

const apiURL = "https://jsonplaceholder.typicode.com/todos";

const getData = async () => {
    const res = await fetch(apiURL)
    if (!res.ok) throw new Error('Bad response')
    const items = await res.json()
    return items.slice(0, 20)
}

export const todos = readable([], set => {
    // called when the store is first subscribed (when subscribers goes from 0 to 1)
    getData()
        .then(set)
        .catch(err => {
            console.error('Failed to fetch', err)
        })
    return () => {
        // you can do cleanup here if needed
    }
})

Finally, in .svelte components, you can prefix stores with a $ to directly access their value. With this notation, Svelte will automatically subscribe to the store when needed, and unsubscribe from it when the component is destroyed.

So in your example, using our readable todos store above, you can change your component to simply this:

<script>
  import { todos } from './store.js';
</script>

<h1>Todos:</h1>

{#each $todos as item}  
  <p>{item.title}</p>
{/each}
like image 199
rixo Avatar answered Sep 17 '22 11:09

rixo