如何坚持苗条的商店
How to persist svelte store
是否有任何直接选项可以持久保存 svelte 存储数据,以便即使刷新页面也可以使用数据。
我没有使用本地存储,因为我希望这些值是反应性的。
您可以手动创建对商店的订阅并将更改保存到 localStorage,还可以使用 localStorage 中的潜在值作为默认值。
例子
<script>
import { writable } from "svelte/store";
const store = writable(localStorage.getItem("store") || "");
store.subscribe(val => localStorage.setItem("store", val));
</script>
<input bind:value={$store} />
您可能还想看看这个 https://github.com/andsala/svelte-persistent-store
此外,如果您使用 sapper 并且不想在服务器上 运行 某些东西,您可以使用 onMount 钩子
onMount(() => {
console.log('I only run in the browser');
});
来自 https://github.com/higsch/higsch.me/blob/master/content/post/2019-06-21-svelte-local-storage.md,作者:Matthias Stahl:
假设我们有一个名为 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 the store
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 the useLocalStorage
function to enable the persistent state.
这在 Routify. For Sapper 中对我来说非常有效,JHeth 建议“只需将 count.useLocalStorage()
放在 onMount
或 if (process.browser)
中使用商店的组件中。”
如果有人需要使用 JavaScript 个对象:
export const stored_object = writable(
localStorage.stored_object? JSON.parse(localStorage.stored_object) : {});
stored_object.subscribe(val => localStorage.setItem("stored_object",JSON.stringify(val)));
好处是您可以使用 $shorthand 访问可写对象,例如
<input type="text" bind:value={$stored_object.name}>
<input type="text" bind:value={$stored_object.price}>
TLDR: 这是一个函数,不仅可以设置和获取,还可以删除。
function persistent(name) {
const value = writable(localStorage.getItem(name));
value.subscribe(val => [null, undefined].includes(val) ? localStorage.removeItem(name) : localStorage.setItem(name, val));
return value;
}
export const my_token = persistent('token');
推理:与直觉相反,localStorage.setItem('someval', null)
不会为下一个 localStorage.getItem('someval')
设置 return null,但 "null"
可能不是人们想要的。因此,这也会检查 undefined 和 null 并相应地删除该项目。
此函数将 svelte store 与 localStorage 同步。如果没有存储值,它会采用 initValue 参数。
我还添加了 Typescript。
import { writable, Writable } from 'svelte/store';
const wStorage = <T>(key: string, initValue: T): Writable<T> => {
const storedValueStr = localStorage.getItem(key);
const storedValue: T = JSON.parse(storedValueStr);
const store = writable(storedValueStr != null ? storedValue : initValue);
store.subscribe((val) => {
localStorage.setItem(key, JSON.stringify(val));
})
return store;
}
export default wStorage;
然后您可以在其他地方使用该功能,就像您习惯使用 writable
:
const count = wStorage<number>('count', 0);
编辑: 如果您在您的应用中使用 SSR 并且不想使用 onMount
或检查每个可写方法的 if (process.browser)
。这是修改后的版本:
const wStorage = <T>(key: string, initValue: T): Writable<T> => {
const store = writable(initValue);
if (typeof Storage === 'undefined') return store;
const storedValueStr = localStorage.getItem(key);
if (storedValueStr != null) store.set(JSON.parse(storedValueStr));
store.subscribe((val) => {
localStorage.setItem(key, JSON.stringify(val));
})
return store;
}
使用 svelte 3.38 和 svelte-kit (Sapper 的后继者),我使用:
<script>
import { onMount } from 'svelte';
import { writable } from "svelte/store";
let value;
onMount(() => {
value = writable(localStorage.getItem("storedValue") || "defaut value");
value.subscribe(val => localStorage.setItem("storedValue", val));
})
</script>
<input bind:value={$value} />
localStorage
不可用 onMount()
对于 Svelte Kit,我遇到了 SSR 问题。
这是我基于 Svelte Kit FAQ, the and the .
的解决方案
作为奖励,如果 localStorage
发生变化(例如在不同的选项卡中),此解决方案还会更新可写内容。所以这个解决方案跨标签工作。参见 Window: storage event
将其放入打字稿文件中,例如$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
可以这样使用:
import storage from '$lib/store'
interface Auth {
jwt: string
}
export const auth = storage<Auth>("auth", { jwt: "" })
适合我的精简版 3.44.1
。
src/store.js 文件:
import { writable } from "svelte/store";
import { browser } from "$app/env"
export const fontSize = writable(browser && localStorage.getItem("fontSize") || "15");
fontSize.subscribe((value) => {
if (browser) return localStorage.setItem("fontSize", value)
});
这是我书中的示例,希望对您有所帮助。
从我的一个项目中复制了这段代码
$lib/savable.ts
import type { Writable, StartStopNotifier, Unsubscriber } from 'svelte/types/runtime/store';
import { writable } from 'svelte/store';
const attach = (writable: Writable<unknown>, key='store'): void =>{
const json = localStorage.getItem(key);
if (json) {
writable.set(JSON.parse(json));
}
writable.subscribe(current => {
localStorage.setItem(key, JSON.stringify(current));
});
}
interface Savable<T> extends Writable<T> {
mount(localstore: Storage): void
dismount(localstore: Storage): JSON
unsub: Unsubscriber
}
function savable<T>(key: string, value?: T, start?: StartStopNotifier<T>): Savable<T>{
const base = writable(value, start)
return {
...base,
mount(localstore) {
if(this.mounted) throw new Error("Already mounted");
this.mounted = true;
const json = localstore.getItem(key);
if (json) {
base.set(JSON.parse(json));
}
this.unsub = base.subscribe(current => {
localStorage.setItem(key, JSON.stringify(current));
});
console.log(this)
},
dismount(localstore) {
if(!this.mounted) throw new Error("Not mounted");
const json = JSON.parse(localstore.getItem(key))
this.unsub()
localstore.removeItem(key)
return json
},
unsub() {
throw new Error('Cannot unsubscribe when not subscribed')
}
}
}
export {
attach,
savable,
};
export type {
Savable
}
export default savable
这里是 index.svelte
中使用的可保存文件的示例
<!—- Typescript is not required —->
<script lang=ts>
import savable from `$lib/savable`;
const value = savable(‘input_value’);
import { onMount } from ‘svelte’;
onMount(()=>{
value.mount()
})
</script>
<input bind:value={$value}></input>
是否有任何直接选项可以持久保存 svelte 存储数据,以便即使刷新页面也可以使用数据。
我没有使用本地存储,因为我希望这些值是反应性的。
您可以手动创建对商店的订阅并将更改保存到 localStorage,还可以使用 localStorage 中的潜在值作为默认值。
例子
<script>
import { writable } from "svelte/store";
const store = writable(localStorage.getItem("store") || "");
store.subscribe(val => localStorage.setItem("store", val));
</script>
<input bind:value={$store} />
您可能还想看看这个 https://github.com/andsala/svelte-persistent-store
此外,如果您使用 sapper 并且不想在服务器上 运行 某些东西,您可以使用 onMount 钩子
onMount(() => {
console.log('I only run in the browser');
});
来自 https://github.com/higsch/higsch.me/blob/master/content/post/2019-06-21-svelte-local-storage.md,作者:Matthias Stahl:
假设我们有一个名为 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.
这在 Routify. For Sapper 中对我来说非常有效,JHeth 建议“只需将 count.useLocalStorage()
放在 onMount
或 if (process.browser)
中使用商店的组件中。”
如果有人需要使用 JavaScript 个对象:
export const stored_object = writable(
localStorage.stored_object? JSON.parse(localStorage.stored_object) : {});
stored_object.subscribe(val => localStorage.setItem("stored_object",JSON.stringify(val)));
好处是您可以使用 $shorthand 访问可写对象,例如
<input type="text" bind:value={$stored_object.name}>
<input type="text" bind:value={$stored_object.price}>
TLDR: 这是一个函数,不仅可以设置和获取,还可以删除。
function persistent(name) {
const value = writable(localStorage.getItem(name));
value.subscribe(val => [null, undefined].includes(val) ? localStorage.removeItem(name) : localStorage.setItem(name, val));
return value;
}
export const my_token = persistent('token');
推理:与直觉相反,localStorage.setItem('someval', null)
不会为下一个 localStorage.getItem('someval')
设置 return null,但 "null"
可能不是人们想要的。因此,这也会检查 undefined 和 null 并相应地删除该项目。
此函数将 svelte store 与 localStorage 同步。如果没有存储值,它会采用 initValue 参数。
我还添加了 Typescript。
import { writable, Writable } from 'svelte/store';
const wStorage = <T>(key: string, initValue: T): Writable<T> => {
const storedValueStr = localStorage.getItem(key);
const storedValue: T = JSON.parse(storedValueStr);
const store = writable(storedValueStr != null ? storedValue : initValue);
store.subscribe((val) => {
localStorage.setItem(key, JSON.stringify(val));
})
return store;
}
export default wStorage;
然后您可以在其他地方使用该功能,就像您习惯使用 writable
:
const count = wStorage<number>('count', 0);
编辑: 如果您在您的应用中使用 SSR 并且不想使用 onMount
或检查每个可写方法的 if (process.browser)
。这是修改后的版本:
const wStorage = <T>(key: string, initValue: T): Writable<T> => {
const store = writable(initValue);
if (typeof Storage === 'undefined') return store;
const storedValueStr = localStorage.getItem(key);
if (storedValueStr != null) store.set(JSON.parse(storedValueStr));
store.subscribe((val) => {
localStorage.setItem(key, JSON.stringify(val));
})
return store;
}
使用 svelte 3.38 和 svelte-kit (Sapper 的后继者),我使用:
<script>
import { onMount } from 'svelte';
import { writable } from "svelte/store";
let value;
onMount(() => {
value = writable(localStorage.getItem("storedValue") || "defaut value");
value.subscribe(val => localStorage.setItem("storedValue", val));
})
</script>
<input bind:value={$value} />
localStorage
不可用 onMount()
对于 Svelte Kit,我遇到了 SSR 问题。
这是我基于 Svelte Kit FAQ, the
作为奖励,如果 localStorage
发生变化(例如在不同的选项卡中),此解决方案还会更新可写内容。所以这个解决方案跨标签工作。参见 Window: storage event
将其放入打字稿文件中,例如$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
可以这样使用:
import storage from '$lib/store'
interface Auth {
jwt: string
}
export const auth = storage<Auth>("auth", { jwt: "" })
适合我的精简版 3.44.1
。
src/store.js 文件:
import { writable } from "svelte/store";
import { browser } from "$app/env"
export const fontSize = writable(browser && localStorage.getItem("fontSize") || "15");
fontSize.subscribe((value) => {
if (browser) return localStorage.setItem("fontSize", value)
});
这是我书中的示例,希望对您有所帮助。
从我的一个项目中复制了这段代码
$lib/savable.ts
import type { Writable, StartStopNotifier, Unsubscriber } from 'svelte/types/runtime/store';
import { writable } from 'svelte/store';
const attach = (writable: Writable<unknown>, key='store'): void =>{
const json = localStorage.getItem(key);
if (json) {
writable.set(JSON.parse(json));
}
writable.subscribe(current => {
localStorage.setItem(key, JSON.stringify(current));
});
}
interface Savable<T> extends Writable<T> {
mount(localstore: Storage): void
dismount(localstore: Storage): JSON
unsub: Unsubscriber
}
function savable<T>(key: string, value?: T, start?: StartStopNotifier<T>): Savable<T>{
const base = writable(value, start)
return {
...base,
mount(localstore) {
if(this.mounted) throw new Error("Already mounted");
this.mounted = true;
const json = localstore.getItem(key);
if (json) {
base.set(JSON.parse(json));
}
this.unsub = base.subscribe(current => {
localStorage.setItem(key, JSON.stringify(current));
});
console.log(this)
},
dismount(localstore) {
if(!this.mounted) throw new Error("Not mounted");
const json = JSON.parse(localstore.getItem(key))
this.unsub()
localstore.removeItem(key)
return json
},
unsub() {
throw new Error('Cannot unsubscribe when not subscribed')
}
}
}
export {
attach,
savable,
};
export type {
Savable
}
export default savable
这里是 index.svelte
<!—- Typescript is not required —->
<script lang=ts>
import savable from `$lib/savable`;
const value = savable(‘input_value’);
import { onMount } from ‘svelte’;
onMount(()=>{
value.mount()
})
</script>
<input bind:value={$value}></input>