Svelte中的状态管理
状态管理一般用于全局共用的一些数据的管理。关于状态管理,在其他的框架中都默认没有提供,都是通过新的库来支持的。比如Vuex
和Redux
。但在Svelte
中内置了状态管理,而且用法非常简单。在Svelte
中关于状态管理的函数都封装在svelte/store
模块中,此模块可以导出readable
,writable
,derived
的功能。
readable
通过readable
创建的状态(数据),在外部不能直接修改,只能在其内部更改。第一个参数是初始值,可为null
,undefined
。第二个参数是一个函数,函数接受一个set
参数(set
是一个函数用于处理内部数据),如果返回一个函数,则在取消订阅时会被调用。
<script>
import { readable } from 'svelte/store';
const double = (val) => val * 2;
let count = readable(null, (set) => {
let i = 1;
set(i);
const interval = setInterval(() => set(++i), 1000);
return () => clearInterval(interval);
});
</script>
<h1>{double($count)}</h1>
$count
是一个语法糖,后续会说明
writable
通过writable
创建的状态(数据),在外部可以通过update
更新,set
设置值,subscribe
订阅状态的改变(subscribe
返回一个函数用于取消订阅)。
<script>
import { onDestroy } from 'svelte';
import { writable } from 'svelte/store';
let count = writable(0);
let countValue = 0;
const unSubscribe = count.subscribe((val) => (countValue = val));
const onSub = () => count.update((n) => n - 1);
const onAdd = () => count.update((n) => n + 1);
const onReset = () => count.set(0);
onDestroy(unSubscribe);
</script>
<h1>countValue:{countValue}</h1>
<button on:click={onSub}>-</button>
<button on:click={onAdd}>+</button>
<button on:click={onReset}>reset</button>
上面的例子中,可以通过$count
进行精简代码,当使用$count
时可以自动订阅状态变化以及在组件销毁时取消状态的订阅,而且$count
是响应式的,即:count.update(val => val + 1)
可以写成$count += 1
。
<script>
import { writable } from 'svelte/store';
let count = writable(0);
const onSub = () => count.update((n) => n - 1);
const onAdd = () => count.update((n) => n + 1);
const onReset = () => count.set(0);
</script>
<h1>count:{$count}</h1>
<button on:click={onSub}>-</button>
<button on:click={onAdd}>+</button>
<button on:click={onReset}>reset</button>
derived
通过derived
可以通过状态来派生出来另一个状态,当依赖的状态发生变化时则立即调用其回调。回调函数接受三个参数:第一个参数是依赖的状态。第二个参数是回调函数,回调函数第一个参数是是依赖的状态变化之后的值,第二个参数是set
函数用于设置新的派生状态,此函数中可以进行异步操作。第三个参数是一个默认值,当回调函数是一个异步函数时,此值才有效。
此外,如果不使用
set
函数,可以直接返回一个值作为派生状态。但是如果有set
函数,则需要用set
函数来设置。
<script>
import { writable, derived } from 'svelte/store';
let count = writable(0);
let doubleCount = derived(count, ($val) => $val * 2);
let doubleSetCount = derived(count, ($val, set) => set($val * 2));
let asyncDoubleCount = derived(
count,
async ($val, set) => {
const data = await new Promise((resolve) => {
setTimeout(() => {
resolve($val * 4);
}, 1000);
});
set(data);
},
'loading'
);
const onAdd = () => $count++;
let time = writable(new Date());
let timer = derived(time, ($time, set) => {
const interval = setInterval(() => set(new Date()), 1000);
return () => clearInterval(interval);
});
</script>
<h1>count: {$count}</h1>
<h1>doubleCount: {$doubleCount}</h1>
<h1>doubleSetCount: {$doubleSetCount}</h1>
<h1>asyncDoubleCount: {$asyncDoubleCount}</h1>
<button on:click={onAdd}>+1</button>
<h1>timer: {$timer}</h1>
get
如果你仅仅是想获取状态值,可以通过get
来获取,这个函数只是获取当前状态的值。
<script>
import { writable, get } from 'svelte/store';
let count = writable(0);
console.log(get(count));
const onAdd = () => {
$count++;
console.log(get(count));
};
</script>
<h1>count: {$count}</h1>
<button on:click={onAdd}>+1</button>
自定义 store
只要一个对象实现了subscribe
方法,那么就是一个store
。我们可以通过svelte/store
提供的模块来对状态进行封装。
countStore.js
import { writable } from 'svelte/store';
export const useCount = () => {
const { subscribe, set, update } = writable(0);
return {
subscribe,
sub: () => update((val) => val - 1),
add: () => update((val) => val + 1),
reset: () => set(0)
};
};
App.svelte
<script>
import { useCount } from './countStore';
const count = useCount();
</script>
<h1>count:{$count}</h1>
<button on:click={count.sub}>-</button>
<button on:click={count.add}>+</button>
<button on:click={count.reset}>reset</button>