How to persist svelte store
You can manually create a subscription to your store and persist the changes to localStorage and also use the potential value in localStorage as default value.
Example
<script>
import { writable } from "svelte/store";
const store = writable(localStorage.getItem("store") || "");
store.subscribe(val => localStorage.setItem("store", val));
</script>
<input bind:value={$store} />
For Svelte Kit I had issues with SSR. This was my solution based on the Svelte Kit FAQ, the answer by Matyanson and the answer by Adnan Y.
As a bonus this solution also updates the writable if the localStorage
changes (e.g. in a different tab). So this solution works across tabs. See the Window: storage event
Put this into a typescript file e.g. $lib/store.ts
:
import { browser } from '$app/env';
import type { Writable } from 'svelte/store';
import { writable, get } from 'svelte/store'
const storage = <T>(key: string, initValue: T): Writable<T> => {
const store = writable(initValue);
if (!browser) return store;
const storedValueStr = localStorage.getItem(key);
if (storedValueStr != null) store.set(JSON.parse(storedValueStr));
store.subscribe((val) => {
if ([null, undefined].includes(val)) {
localStorage.removeItem(key)
} else {
localStorage.setItem(key, JSON.stringify(val))
}
})
window.addEventListener('storage', () => {
const storedValueStr = localStorage.getItem(key);
if (storedValueStr == null) return;
const localValue: T = JSON.parse(storedValueStr)
if (localValue !== get(store)) store.set(localValue);
});
return store;
}
export default storage
This can be used like this:
import storage from '$lib/store'
interface Auth {
jwt: string
}
export const auth = storage<Auth>("auth", { jwt: "" })
From https://github.com/higsch/higsch.me/blob/master/content/post/2019-06-21-svelte-local-storage.md by Matthias Stahl:
Say we have a store variable called count
.
// store.js import { writable } from 'svelte/store'; export const count = writable(0); // App.svelte import { count } from 'store.js';
In order to make the store persistent, just include the function
useLocalStorage
to thestore
object.// store.js import { writable } from 'svelte/store'; const createWritableStore = (key, startValue) => { const { subscribe, set } = writable(startValue); return { subscribe, set, useLocalStorage: () => { const json = localStorage.getItem(key); if (json) { set(JSON.parse(json)); } subscribe(current => { localStorage.setItem(key, JSON.stringify(current)); }); } }; } export const count = createWritableStore('count', 0); // App.svelte import { count } from 'store.js'; count.useLocalStorage();
Then, in your
App.svelte
just invoke theuseLocalStorage
function to enable the persistent state.
This worked perfectly for me in Routify. For Sapper, JHeth suggests "just place count.useLocalStorage()
in onMount
or if (process.browser)
in the component consuming the store. "