svelte/store 模块导出了用于创建 可读、可写 和 派生 存储的功能。
请记住,你并不 必须 使用这些函数才能在组件中享受 响应式的 $store 语法。任何正确实现 .subscribe、取消订阅和(可选的).set 的对象都是有效的存储,并且可以与特殊语法以及 Svelte 的内置 派生 存储 一起工作。
这使得你可以将几乎所有其他反应性状态处理库包装起来,用于 Svelte。阅读更多关于 store 契约 来了解正确实现的样子。
writable
function writable<T>(value?: T | undefined,start?: StartStopNotifier<T> | undefined): Writable<T>;
创建一个可写存储的函数,其值可以从 ‘外部’ 组件设置。它被创建为一个具有额外 set 和 update 方法的对象。
set 是一个方法,它接受一个参数,即要设置的值。如果存储的值尚未与参数值相等,则将存储的值设置为参数的值。
update 是一个方法,它接受一个参数,即回调函数。回调函数接受现有的存储值作为其参数,并返回要设置为存储的新值。
store.js
import { writable } from 'svelte/store';const count = writable(0);count.subscribe((value) => {console.log(value);}); // logs '0'count.set(1); // logs '1'count.update((n) => n + 1); // logs '2'
store.ts
import { writable } from 'svelte/store';const count = writable(0);count.subscribe((value) => {console.log(value);}); // logs '0'count.set(1); // logs '1'count.update((n) => n + 1); // logs '2'
如果将函数作为第二个参数传递,当订阅者数量从零变为一时(而不是从一开始),将调用该函数。该函数将传递一个 set 函数,用于更改存储的值,以及一个 update 函数,其工作方式与存储上的 update 方法相同,接受一个回调函数,根据旧值计算存储的新值。它必须返回一个在订阅者数量从一变为零时调用的 stop 函数。
store.js
import { writable } from 'svelte/store';const count = writable(0, () => {console.log('got a subscriber');return () => console.log('no more subscribers');});count.set(1); // does nothingconst unsubscribe = count.subscribe((value) => {console.log(value);}); // logs 'got a subscriber', then '1'unsubscribe(); // logs 'no more subscribers'
store.ts
import { writable } from 'svelte/store';const count = writable(0, () => {console.log('got a subscriber');return () => console.log('no more subscribers');});count.set(1); // does nothingconst unsubscribe = count.subscribe((value) => {console.log(value);}); // logs 'got a subscriber', then '1'unsubscribe(); // logs 'no more subscribers'
请注意,当可写存储被销毁时,其值会丢失,例如当页面刷新时。然而,你可以编写自己的逻辑,将值同步到例如 localStorage。
readable
function readable<T>(value?: T | undefined,start?: StartStopNotifier<T> | undefined): Readable<T>;
创建一个存储,其值不能从 ‘外部’ 设置,第一个参数是存储的初始值,readable 的第二个参数与 writable 的第二个参数相同。
import { readable } from 'svelte/store';const time = readable(new Date(), (set) => {set(new Date());const interval = setInterval(() => {set(new Date());}, 1000);return () => clearInterval(interval);});const ticktock = readable('tick', (set, update) => {const interval = setInterval(() => {update((sound) => (sound === 'tick' ? 'tock' : 'tick'));}, 1000);});
derived
function derived<S extends Stores, T>(stores: S,fn: (values: StoresValues<S>,set: (value: T) => void,update: (fn: Updater<T>) => void) => Unsubscriber | void,initial_value?: T | undefined): Readable<T>;
function derived<S extends Stores, T>(stores: S,fn: (values: StoresValues<S>) => T,initial_value?: T | undefined): Readable<T>;
从一个或多个其他存储中派生一个存储。回调最初在第一个订阅者订阅时运行,然后每当存储依赖项更改时运行。
在最简单的版本中,derived 接受一个单一的存储,并且回调返回一个派生值。
import { derived } from 'svelte/store';const doubled = derived(a, ($a) => $a * 2);
回调可以通过接受第二个参数 set 和一个可选的第三个参数 update 异步设置值,当合适的时候调用它们中的一个或两个。
在这种情况下,你也可以向 derived 传递第三个参数 —— 在 set 或 update 首次被调用之前派生存储的初始值。如果没有指定初始值,存储的初始值将为 undefined。
import { derived } from 'svelte/store';const delayed = derived(a,($a, set) => {setTimeout(() => set($a), 1000);},2000);const delayedIncrement = derived(a, ($a, set, update) => {set($a);setTimeout(() => update((x) => x + 1), 1000);// every time $a produces a value, this produces two// values, $a immediately and then $a + 1 a second later});
如果从回调中返回一个函数,它将在 a) 回调再次运行时,或 b) 最后一个订阅者取消订阅时被调用。
import { derived } from 'svelte/store';const tick = derived(frequency,($frequency, set) => {const interval = setInterval(() => {set(Date.now());}, 1000 / $frequency);return () => {clearInterval(interval);};},2000);
在两种情况下,可以作为第一个参数传递一个参数数组,而不是单一存储。
import { derived } from 'svelte/store';const summed = derived([a, b], ([$a, $b]) => $a + $b);const delayed = derived([a, b], ([$a, $b], set) => {setTimeout(() => set($a + $b), 1000);});
readonly
function readonly<T>(store: Readable<T>): Readable<T>;
这个简单的辅助函数使存储变为只读。你仍然可以使用这个新的可读存储来订阅原始存储的更改。
import { readonly, writable } from 'svelte/store';const writableStore = writable(1);const readableStore = readonly(writableStore);Property 'set' does not exist on type 'Readable<number>'.2339Property 'set' does not exist on type 'Readable<number>'.readableStore.subscribe(console.log);writableStore.set(2); // console: 2readableStore.set(2); // ERROR
get
function get<T>(store: Readable<T>): T;
通常,你应该通过订阅存储并使用随时间变化的值来读取存储的值。偶尔,你可能需要检索你未订阅的存储的值。get 允许你这样做。
这是通过创建一个订阅、读取值,然后取消订阅来实现的。因此,不建议在热点代码路径中使用。
import { get } from 'svelte/store';const value = get(store);
类型
Readable
Readable 接口用于订阅。
interface Readable<T> {…}
subscribe(this: void, run: Subscriber<T>, invalidate?: Invalidator<T>): Unsubscriber;
run订阅回调invalidate清理回调
订阅值更改。
StartStopNotifier
开始和停止通知回调。当第一个订阅者订阅时调用此函数。
type StartStopNotifier<T> = (set: (value: T) => void,update: (fn: Updater<T>) => void) => void | (() => void);
Subscriber
Callback to inform of a value updates.
type Subscriber<T> = (value: T) => void;
Unsubscriber
Unsubscribes from value updates.
type Unsubscriber = () => void;
Updater
Callback to update a value.
type Updater<T> = (value: T) => T;
Writable
Writable 接口用于更新和订阅。
interface Writable<T> extends Readable<T> {…}
set(this: void, value: T): void;
valueto set
Set value and inform subscribers.
update(this: void, updater: Updater<T>): void;
updatercallback
Update value using callback and inform subscribers.
