DEV Community

Nico Heinrich
Nico Heinrich

Posted on • Edited on

1 1

Svelte Stores x Dexie 2.0

My first post was about connecting a svelte store to the indexedDB. This one will be an update on the same topic. Keep reading if you want a completely different approach that is more practial in most cases!

What I want to achieve

I want to save data in the indexedDB and use that data in my app.

The problem

As the idexedDB works asynchronously, most of the time the page will be loaded before the data, which results in an ugly flicker when the elements are updated due to svelte's reactive nature. So, the data should be loaded from a store rather than the indexedDB itself whenever possible. Obviously, it has to be loaded once on the initial page load — but with an SPA that is it!

The solution

A svelte store with a special function that gets the data from the indexedDB. That is basically it but there are some important subtleties that I will explain in a minute.

Install Dexie

In order to use this, you need to install Dexie.js:

npm install dexie
Enter fullscreen mode Exit fullscreen mode

Create db.js

This is the very minimalistic set-up for your indexedDB that sits in your lib folder:

import Dexie from 'dexie';

export const db = new Dexie("user");

db.version(1).stores({
  user: "key, value"
});
Enter fullscreen mode Exit fullscreen mode

Create stores.js

This is the actual store that you can use in your +page.svelte. As you can see, it has a function called sync which gets the data from the indexedDB with Dexie and sets the data of userData. It also returns a promise which will be very handy in a second.

import { writable } from "svelte/store";
import { db } from "$lib/db";

export const userData = writable([]);

userData.sync = function() {
    return new Promise (async (resolve, reject) => {
        try {
            const data = await db.user.toArray();
            userData.set(data);

            resolve();
        } catch (error) {
            console.error(error);

            reject (error);
        }
    })
}
Enter fullscreen mode Exit fullscreen mode

How To Load

import { userData } from "@stores"; // I am using an alias here

<script>
    function handleMount() {
        userData.sync()
    }

    onMount(handleMount);
</script>

<main>
    {#each $userData as data}
        <p>{data.name}, {data.age}</p>
    {/each}
</main>
Enter fullscreen mode Exit fullscreen mode

Do Stuff When The Data Has Been Loaded

Sometimes you need to wait for the data until you can call a function. This is no longer a problem, as you can just use .then after the sync-Function.

import { userData } from "@stores"; // I am using an alias here

<script>
    function handleMount() {
        userData.sync()
        .then(() => {
            // do stuff!
        })
    }

    onMount(handleMount);
</script>

<main>
    {#each $userData as data}
        <p>{data.name}, {data.age}</p>
    {/each}
</main>
Enter fullscreen mode Exit fullscreen mode

How To Save

To save data in the indexedDB, simply use the Dexie API and then update the store:

    function saveData() {
        db.user.put({ name, inputValue });
        userData.sync()
    }
Enter fullscreen mode Exit fullscreen mode

I really like this work flow, as it gives me way more control than the last solution (and Dexie's liveQuery) but is still really, really simple!

Cheers,

Nico

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (2)

Collapse
 
owennewo profile image
Owen Williams • Edited

Thanks for putting this together, helpful. I think there are a couple of mistakes:

  1. progress should be name of table i.e. user
const data = await db.user.toArray();
Enter fullscreen mode Exit fullscreen mode
  1. The object you 'put' is not valid json it should be something like {'key': name, 'value': inputValue }
db.user.put({'key': name, 'value': inputValue });
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dskvr profile image
Sandwich • Edited

The object you 'put' is not valid json it should be something like {'key': name, 'value': inputValue }

From what I can see that's not the issue. Should instead be

{ name, age } 
//same as 
{ name: name, age: age }
Enter fullscreen mode Exit fullscreen mode

Note: Table.put requires a JSObject not JSON

And the function should probably have arguments

    function putUserData(name, age) {
        db.user.put({ name, age });
        userData.sync()
    }
Enter fullscreen mode Exit fullscreen mode

And should probably be async, added arrow functions syntax for fun and profit

    const putUserData = async (name, age) => {
        await db.user.put({ name, age });
        await userData.sync()
    }
Enter fullscreen mode Exit fullscreen mode

Billboard image

Deploy and scale your apps on AWS and GCP with a world class developer experience

Coherence makes it easy to set up and maintain cloud infrastructure. Harness the extensibility, compliance and cost efficiency of the cloud.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay