class stores for svelte.
npm i classy-store
# yarn add classy-store
You must enable experimentalDecorators
in your tsconfig to use the @mutator
decorator.
import { mutator, Store } from "classy-store";
export class Spike extends Store<Spike> {
name: string;
count: number;
constructor(name: string, count?: number) {
super();
this.name = name;
this.count = count ?? 0;
}
@mutator
inc(n = 1) {
this.count = this.count + n;
return this.count;
}
@mutator
async delayed() {
await new Promise((res) => setTimeout(res, 500));
this.count + 100;
}
}
<script lang="ts">
import { Spike } from '$lib/spike';
let spike = new Spike('this is a store');
</script>
<h1>Hello {$spike.name}</h1>
<h2>Bindings</h2>
<input bind:value={$spike.name} />
<h3>Using @mutator allows for methods:</h3>
<button on:click={() => $spike.inc()}>{$spike.count}</button>
<h3>methods can be promises:</h3>
<button on:click={() => { $spike.delayed(); }}>level up</button>
@mutator
is a wrapper around your method which executes store.broadcast
after your method is finished altering the store's state.
Promise
, broadcast
is called immediately and again when the promise is resolved or rejected.Promise
is returned, executing[methodName]
is set to Execution.Running
. Promise
resolves successfully, executing[methodName]
is set to Execution.Resolved
. Promise
is rejected, executing[methodName]
is set to Execution.Rejected
Promise
is rejected, an "error"
event is emitted with the reason.<script lang="ts">
import { Spike } from '$lib/spike';
import { Execution } from 'classy-store'
let spike = new Spike('this is a store');
let disabled = false
$: disabled = $spike.executing.delayed === Execution.Running
</script>
<button on:click={spike.delayed()} {disabled || undefined}>{$spike.count}</button>
The default error handler stores _errors
in a queue on your store.
The max size a configurable by setting maxErrorsToStore
on Options
passed to the Store
constructor.
The stores can be derived:
<script lang="ts">
import { Spike } from "$lib/spike";
import { derived } from "svelte/store";
let spike = new Spike("this is a store");
const screaming = derived(spike, ($spike) => $spike.name.toUpperCase());
</script>
<h1>hello {$screaming}</h1>
<input bind:value="{$spike.name}" />
The stores are event emitters although more work is needed on that front.
If you wish to emit custom events, type your store such as:
interface MyEvents {
example: (value: string) => void;
}
class Spike extends Store<Spike, MyEvents> {
constructor() {
super();
this.emit("example", "example should be typed");
}
}
You can update the store with a new instance or a partial of the fields:
<script lang="ts">
import { Spike } from "$lib/spike";
let spike = new Spike("this is a store");
</script>
<h1>Hello {$spike.name}</h1>
<button on:click={()=> { $spike.set({name:"..."})}}>
Please feel free to create an issue for any question, feedback or bug you encounter.
A very simple javascript REPL is available here.
MIT