参考:Stores / Writable stores • Svelte 教程 | Svelte 中文网
store是什么
在 Svelte 中,store 是一种特殊的对象,用于在组件之间共享状态。可以将 store 视为一个全局的状态容器,所有订阅该 store 的组件都可以读取其值,并在需要时更新其值。store 提供了一种在组件之间传递数据和状态的机制,使得跨组件通信和状态共享变得更加简单和方便。
但store不是普通的JavaScript变量,有自己的特性和使用方式:
-
响应式更新: 当 store 的值发生变化时,所有订阅了该 store 的组件都会自动更新,而不需要手动管理状态的变化和重新渲染的逻辑。
-
集中式管理: store 提供了一个集中式的状态管理中心,用于管理应用程序的全局状态。这使得状态的管理更加清晰和可控,避免了状态分散和混乱的情况。
-
跨组件共享: store 可以在整个应用程序中共享和使用,从而实现跨组件的状态共享。这使得不同组件之间可以方便地共享数据和状态,从而实现更加灵活和可复用的组件设计。
组件之间共享状态,就是多个组件能够访问和修改相同的数据,从而实现数据的共享和同步更新
为什么要用store
普通的变量在 Svelte 中也可以在组件之间传递,但是它们通常只适用于父子组件之间的通信,或者在单个组件内部的状态管理。如果你想要在多个不相关的组件之间共享状态,并且希望当该状态发生变化时能够自动更新所有相关的组件,那么使用 store 会更加方便和合适。
使用 store 的主要优势在于它提供了一种集中式的状态管理机制,能够更方便地管理应用程序的全局状态。而普通的变量通常只能在其所在的组件中使用,需要通过 props 或事件来传递给其他组件,这样会导致组件之间的耦合度增加,同时也增加了状态管理的复杂度。
使用 store 还能够实现跨组件的状态共享,而普通的变量通常只能在父子组件之间传递,无法跨越组件层级。
创建store方法
writable函数
writable函数可以创建一个可写的store
app.svelte
<script>
import { count } from './stores.js';
import Incrementer from './Incrementer.svelte';
import Decrementer from './Decrementer.svelte';
import Resetter from './Resetter.svelte';
let count_value;
const unsubscribe = count.subscribe(value => {
count_value = value;
});
</script>
<h1>The count is {count_value}</h1>
<Incrementer/>
<Decrementer/>
<Resetter/>
Decrementer.svelte
<script>
import { count } from './stores.js';
function decrement() {
count.update(n => n - 1);
}
</script>
<button on:click={decrement}>
-
</button>
Incrementer.svelte
<script>
import { count } from './stores.js';
function increment() {
count.update(n => n + 1);
}
</script>
<button on:click={increment}>
+
</button>
Resetter.svelte
<script>
import { count } from './stores.js';
function reset() {
count.set(0);
}
</script>
<button on:click={reset}>
reset
</button>
stores.js
import { writable } from 'svelte/store';
export const count = writable(0);
在上面的例子中,有很多个svelte文件,这时候用props就不太合适,因为有很多组件了,那就可以用stores,用writable函数创建了一个初始值为0的count变量,每一个组件都可以访问到
readable函数
readable
函数用于创建只读的 store,它适用于那些不需要直接修改值,而是只需要订阅和读取的场景。
stores.js
import { readable } from 'svelte/store';
export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => {
set(new Date());
}, 1000);
return function stop() {
clearInterval(interval);
};
});
App.svelte
<script>
import { time } from './stores.js';
const formatter = new Intl.DateTimeFormat('en', {
hour12: true,
hour: 'numeric',
minute: '2-digit',
second: '2-digit'
});
</script>
<h1>The time is {formatter.format($time)}</h1>
derived属性 stores派生
在 Svelte 中,derived 是一种特殊的可计算属性,它允许你基于其他状态或 store 的值派生出新的值。derived 可以帮助你管理和计算状态,以确保你的应用程序保持简洁和高效。 你可以使用 derived 来创建一个派生的状态,该状态的值取决于其他状态的值。当任一依赖状态发生变化时,派生状态也会相应地更新。
App.svelte
<script>
import { time, elapsed } from './stores.js';
const formatter = new Intl.DateTimeFormat('en', {
hour12: true,
hour: 'numeric',
minute: '2-digit',
second: '2-digit'
});
</script>
<h1>The time is {formatter.format($time)}</h1>
<p>
This page has been open for
{$elapsed} {$elapsed === 1 ? 'second' : 'seconds'}
</p>
stores.js
import { readable, derived } from 'svelte/store';
export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => {
set(new Date());
}, 1000);
return function stop() {
clearInterval(interval);
};
});
const start = new Date();
export const elapsed = derived(
time,
$time => Math.round(($time - start) / 1000)
);
derived可以理解成一个更厉害的更多更多功能的值传递,可以自动更新,可以在里面定义复杂的计算逻辑等等
自定义stores
只要一个对象正确的使用 subscribe ,它就是可以称之为store。因此,使用特定语法来创建自定义 stores变得非常容易
比如在前面的writable例子中,count变量包含了increment、 decrement 和 reset组件,,为了防止暴露set,update方法,可以进行更改
App.svelte
<script>
import { count } from './stores.js';
</script>
<h1>The count is {$count}</h1>
<button on:click={count.increment}>+</button>
<button on:click={count.decrement}>-</button>
<button on:click={count.reset}>reset</button>
stores.js
import { writable } from 'svelte/store';
function createCount() {
const { subscribe, set, update } = writable(0);
return {
subscribe,
increment: () => update(n => n + 1),
decrement: () => update(n => n - 1),
reset: () => set(0)
};
}
export const count = createCount();
绑定store
如果 store可写入的(即具有set
方法),则可以绑定其值,就像可以绑定局部组件状态一样。
App.svelte
<script>
import { name, greeting } from './stores.js';
</script>
<h1>{$greeting}</h1>
<input bind:value={$name}>
<button on:click="{() => $name += '!'}">
<!--这里的$name += '!' 相当于 name.set($name + '!')-->
Add exclamation mark!
</button>
stores.js
import { writable, derived } from 'svelte/store';
export const name = writable('world');
export const greeting = derived(
name,
$name => `Hello ${$name}!`
);