【前端】Svelte:Store 状态管理
Svelte 提供了内置的状态管理系统,通过 writable
、readable
和 derived
三种类型的 Store,可以轻松地在不同组件之间共享状态。相比其他前端框架中需要借助外部库实现状态管理,Svelte 的 Store 内置且使用简单,尤其适用于需要跨组件共享数据的小型应用。
在本教程中,我们将深入学习 Svelte 的 writable
、readable
和 derived
状态管理 API,最后通过 Store 实现组件间的状态共享,构建一个小型应用。
Store 概述
在 Svelte 中,Store 是一种响应式的状态容器,可以将 Store 中的数据绑定到组件,并在数据更新时触发自动渲染。Store 的核心 API 包括三种类型:
writable
:可读可写的 Store,最常用。readable
:只读 Store,一般用于定时更新数据或从外部数据源获取数据。derived
:派生 Store,可根据其他 Store 的变化自动更新。
使用 Store 的主要步骤如下:
- 创建 Store。
- 将 Store 数据绑定到组件。
- 在组件中读取或修改 Store 数据。
writable
:可读写的 Store
writable
是最基础的 Store,支持直接读写。以下示例展示如何创建和使用一个 writable
Store。
创建 writable
Store
首先,通过 writable
创建一个 Store:
// src/stores/counter.js
import { writable } from 'svelte/store';
export const counter = writable(0);
在这个文件中,我们创建了一个名为 counter
的 Store,初始值为 0
。Store 是响应式的,counter
的值发生变化时,所有引用它的组件会自动更新。
在组件中使用 writable
Store
在组件中,我们可以直接导入这个 Store 并绑定到组件变量:
<script>
import { counter } from './stores/counter';
// 通过 `$counter` 访问 counter 的值
function increment() {
counter.update(n => n + 1);
}
</script>
<button on:click={increment}>Increment</button>
<p>Counter: {$counter}</p>
在这个例子中:
- 通过
$counter
可以直接获取counter
的值并绑定到模板中。 - 使用
counter.update
方法来更新 Store 的值。update
接收一个函数,函数的参数是当前值。
readable
:只读的 Store
readable
是一种只读 Store,适用于数据不需要组件内部更改的情况。它可以在特定的时间间隔内自动更新,比如获取时间戳、从 API 获取数据等。
创建 readable
Store
下面是一个定时更新的 readable
Store 示例:
// src/stores/time.js
import { readable } from 'svelte/store';
export const time = readable(new Date(), set => {
const interval = setInterval(() => {
set(new Date());
}, 1000);
// 清除定时器
return () => clearInterval(interval);
});
set
是一个函数,用于更新readable
的值。- 定时器每秒调用
set
,更新 Store 为新的日期和时间。
在组件中使用 readable
Store
<script>
import { time } from './stores/time';
</script>
<p>Current time: {$time}</p>
在这里,$time
将随着时间的变化自动更新,无需手动设置。
derived
:派生的 Store
derived
Store 是根据其他 Store 派生出来的值,当源 Store 发生变化时,派生 Store 也会自动更新。这对于在多个 Store 的基础上计算新值非常有用。
创建 derived
Store
以下示例展示了一个根据 counter
计算出双倍值的派生 Store:
// src/stores/double.js
import { derived } from 'svelte/store';
import { counter } from './counter';
export const doubleCounter = derived(counter, $counter => $counter * 2);
在这个例子中:
doubleCounter
依赖于counter
,每次counter
变化时,doubleCounter
都会更新为counter
的两倍。
在组件中使用 derived
Store
<script>
import { counter } from './stores/counter';
import { doubleCounter } from './stores/double';
function increment() {
counter.update(n => n + 1);
}
</script>
<button on:click={increment}>Increment</button>
<p>Counter: {$counter}</p>
<p>Double Counter: {$doubleCounter}</p>
在这里,$doubleCounter
会随着 $counter
的变化自动更新。
构建小型应用:多组件共享 Store 数据
为了展示如何通过 Store 实现跨组件的数据共享,我们将构建一个小型的计分器应用。该应用包含以下功能:
- 主组件包含增加分数和重置分数的按钮。
- 显示组件实时显示当前分数和派生的状态信息。
创建主 Store
创建一个可写的 score
Store:
// src/stores/score.js
import { writable } from 'svelte/store';
export const score = writable(0);
创建显示状态的派生 Store
根据分数生成一个派生 Store,显示当前状态:
// src/stores/status.js
import { derived } from 'svelte/store';
import { score } from './score';
export const status = derived(score, $score => {
if ($score >= 10) return 'High Score';
if ($score >= 5) return 'Good Score';
return 'Keep Going';
});
主组件:App.svelte
<script>
import { score } from './stores/score';
import ScoreDisplay from './ScoreDisplay.svelte';
function increaseScore() {
score.update(n => n + 1);
}
function resetScore() {
score.set(0);
}
</script>
<button on:click={increaseScore}>Increase Score</button>
<button on:click={resetScore}>Reset Score</button>
<ScoreDisplay />
主组件 App.svelte
包含两个按钮,分别用于增加分数和重置分数,并嵌入了 ScoreDisplay
组件。
显示组件:ScoreDisplay.svelte
<script>
import { score } from './stores/score';
import { status } from './stores/status';
</script>
<p>Score: {$score}</p>
<p>Status: {$status}</p>
ScoreDisplay
组件显示了当前分数和状态信息,通过 score
和 status
共享数据。
总结
Svelte 内置的 writable
、readable
和 derived
Store 简化了状态管理的实现,特别适用于多组件共享数据的小型应用。通过将状态存储在 Store 中,我们可以避免复杂的 props 传递和状态提升问题,使得组件结构更加清晰,且提高了数据共享和维护的便利性。