svelte/store 模块导出了用于创建 可读可写派生 存储的功能。

请记住,你并不 必须 使用这些函数才能在组件中享受 响应式的 $store 语法。任何正确实现 .subscribe、取消订阅和(可选的).set 的对象都是有效的存储,并且可以与特殊语法以及 Svelte 的内置 派生 存储 一起工作。

这使得你可以将几乎所有其他反应性状态处理库包装起来,用于 Svelte。阅读更多关于 store 契约 来了解正确实现的样子。

writable

  1. function writable<T>(
  2. value?: T | undefined,
  3. start?: StartStopNotifier<T> | undefined
  4. ): Writable<T>;

创建一个可写存储的函数,其值可以从 ‘外部’ 组件设置。它被创建为一个具有额外 setupdate 方法的对象。

set 是一个方法,它接受一个参数,即要设置的值。如果存储的值尚未与参数值相等,则将存储的值设置为参数的值。

update 是一个方法,它接受一个参数,即回调函数。回调函数接受现有的存储值作为其参数,并返回要设置为存储的新值。

store.js

  1. import { writable } from 'svelte/store';
  2. const count = writable(0);
  3. count.subscribe((value) => {
  4. console.log(value);
  5. }); // logs '0'
  6. count.set(1); // logs '1'
  7. count.update((n) => n + 1); // logs '2'

store.ts

  1. import { writable } from 'svelte/store';
  2. const count = writable(0);
  3. count.subscribe((value) => {
  4. console.log(value);
  5. }); // logs '0'
  6. count.set(1); // logs '1'
  7. count.update((n) => n + 1); // logs '2'

如果将函数作为第二个参数传递,当订阅者数量从零变为一时(而不是从一开始),将调用该函数。该函数将传递一个 set 函数,用于更改存储的值,以及一个 update 函数,其工作方式与存储上的 update 方法相同,接受一个回调函数,根据旧值计算存储的新值。它必须返回一个在订阅者数量从一变为零时调用的 stop 函数。

store.js

  1. import { writable } from 'svelte/store';
  2. const count = writable(0, () => {
  3. console.log('got a subscriber');
  4. return () => console.log('no more subscribers');
  5. });
  6. count.set(1); // does nothing
  7. const unsubscribe = count.subscribe((value) => {
  8. console.log(value);
  9. }); // logs 'got a subscriber', then '1'
  10. unsubscribe(); // logs 'no more subscribers'

store.ts

  1. import { writable } from 'svelte/store';
  2. const count = writable(0, () => {
  3. console.log('got a subscriber');
  4. return () => console.log('no more subscribers');
  5. });
  6. count.set(1); // does nothing
  7. const unsubscribe = count.subscribe((value) => {
  8. console.log(value);
  9. }); // logs 'got a subscriber', then '1'
  10. unsubscribe(); // logs 'no more subscribers'

请注意,当可写存储被销毁时,其值会丢失,例如当页面刷新时。然而,你可以编写自己的逻辑,将值同步到例如 localStorage

readable

  1. function readable<T>(
  2. value?: T | undefined,
  3. start?: StartStopNotifier<T> | undefined
  4. ): Readable<T>;

创建一个存储,其值不能从 ‘外部’ 设置,第一个参数是存储的初始值,readable 的第二个参数与 writable 的第二个参数相同。

  1. import { readable } from 'svelte/store';
  2. const time = readable(new Date(), (set) => {
  3. set(new Date());
  4. const interval = setInterval(() => {
  5. set(new Date());
  6. }, 1000);
  7. return () => clearInterval(interval);
  8. });
  9. const ticktock = readable('tick', (set, update) => {
  10. const interval = setInterval(() => {
  11. update((sound) => (sound === 'tick' ? 'tock' : 'tick'));
  12. }, 1000);
  13. });

derived

  1. function derived<S extends Stores, T>(
  2. stores: S,
  3. fn: (
  4. values: StoresValues<S>,
  5. set: (value: T) => void,
  6. update: (fn: Updater<T>) => void
  7. ) => Unsubscriber | void,
  8. initial_value?: T | undefined
  9. ): Readable<T>;
  1. function derived<S extends Stores, T>(
  2. stores: S,
  3. fn: (values: StoresValues<S>) => T,
  4. initial_value?: T | undefined
  5. ): Readable<T>;

从一个或多个其他存储中派生一个存储。回调最初在第一个订阅者订阅时运行,然后每当存储依赖项更改时运行。

在最简单的版本中,derived 接受一个单一的存储,并且回调返回一个派生值。

  1. import { derived } from 'svelte/store';
  2. const doubled = derived(a, ($a) => $a * 2);

回调可以通过接受第二个参数 set 和一个可选的第三个参数 update 异步设置值,当合适的时候调用它们中的一个或两个。

在这种情况下,你也可以向 derived 传递第三个参数 —— 在 setupdate 首次被调用之前派生存储的初始值。如果没有指定初始值,存储的初始值将为 undefined

  1. import { derived } from 'svelte/store';
  2. const delayed = derived(
  3. a,
  4. ($a, set) => {
  5. setTimeout(() => set($a), 1000);
  6. },
  7. 2000
  8. );
  9. const delayedIncrement = derived(a, ($a, set, update) => {
  10. set($a);
  11. setTimeout(() => update((x) => x + 1), 1000);
  12. // every time $a produces a value, this produces two
  13. // values, $a immediately and then $a + 1 a second later
  14. });

如果从回调中返回一个函数,它将在 a) 回调再次运行时,或 b) 最后一个订阅者取消订阅时被调用。

  1. import { derived } from 'svelte/store';
  2. const tick = derived(
  3. frequency,
  4. ($frequency, set) => {
  5. const interval = setInterval(() => {
  6. set(Date.now());
  7. }, 1000 / $frequency);
  8. return () => {
  9. clearInterval(interval);
  10. };
  11. },
  12. 2000
  13. );

在两种情况下,可以作为第一个参数传递一个参数数组,而不是单一存储。

  1. import { derived } from 'svelte/store';
  2. const summed = derived([a, b], ([$a, $b]) => $a + $b);
  3. const delayed = derived([a, b], ([$a, $b], set) => {
  4. setTimeout(() => set($a + $b), 1000);
  5. });

readonly

  1. function readonly<T>(store: Readable<T>): Readable<T>;

这个简单的辅助函数使存储变为只读。你仍然可以使用这个新的可读存储来订阅原始存储的更改。

  1. import { readonly, writable } from 'svelte/store';
  2. const writableStore = writable(1);
  3. const readableStore = readonly(writableStore);
  4. Property 'set' does not exist on type 'Readable<number>'.2339Property 'set' does not exist on type 'Readable<number>'.
  5. readableStore.subscribe(console.log);
  6. writableStore.set(2); // console: 2
  7. readableStore.set(2); // ERROR

get

  1. function get<T>(store: Readable<T>): T;

通常,你应该通过订阅存储并使用随时间变化的值来读取存储的值。偶尔,你可能需要检索你未订阅的存储的值。get 允许你这样做。

这是通过创建一个订阅、读取值,然后取消订阅来实现的。因此,不建议在热点代码路径中使用。

  1. import { get } from 'svelte/store';
  2. const value = get(store);

类型

Readable

Readable 接口用于订阅。

  1. interface Readable<T> {…}
  1. subscribe(this: void, run: Subscriber<T>, invalidate?: Invalidator<T>): Unsubscriber;
  • run 订阅回调
  • invalidate 清理回调

订阅值更改。

StartStopNotifier

开始和停止通知回调。当第一个订阅者订阅时调用此函数。

  1. type StartStopNotifier<T> = (
  2. set: (value: T) => void,
  3. update: (fn: Updater<T>) => void
  4. ) => void | (() => void);

Subscriber

Callback to inform of a value updates.

  1. type Subscriber<T> = (value: T) => void;

Unsubscriber

Unsubscribes from value updates.

  1. type Unsubscriber = () => void;

Updater

Callback to update a value.

  1. type Updater<T> = (value: T) => T;

Writable

Writable 接口用于更新和订阅。

  1. interface Writable<T> extends Readable<T> {…}
  1. set(this: void, value: T): void;
  • value to set

Set value and inform subscribers.

  1. update(this: void, updater: Updater<T>): void;
  • updater callback

Update value using callback and inform subscribers.