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 nothing
const 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 nothing
const 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: 2
readableStore.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;
value
to set
Set value and inform subscribers.
update(this: void, updater: Updater<T>): void;
updater
callback
Update value using callback and inform subscribers.