Svelte is the smallest JS framework, but even so, it contains many built-in features. One of them is a svelte/store
. But why we need to use a third-party store? @storeon/svelte
has several advantages compared with the built-in one.
npm install -S @storeon/svelte
or
yarn add @storeon/svelte
Create store using storeon
module:
store.js
import { createStoreon } from 'storeon'
let counter = store => {
store.on('@init', () => ({ count: 0 }))
store.on('inc', ({ count }) => ({ count: count + 1 }))
}
export const store = createStoreon([counter])
Using TypeScript you can pass State
and Events
interface to the createStoreon
function:
store.ts
import { StoreonModule, createStoreon } from 'storeon'
interface State {
count: number
}
interface Events {
'inc': undefined
'set': number
}
let counter = (store: StoreonModule<State, Events>) => {
store.on('@init', () => ({ count: 0 }))
store.on('inc', ({ count }) => ({ count: count + 1 }))
store.on('set', (_, event) => ({ count: event}))
};
export const store = createStoreon<State, Events>([counter])
App.svelte
Provide store to Svelte Context using provideStoreon
from @storeon/svelte
<script>
import { provideStoreon } from '@storeon/svelte'
import { store } from './store'
import Counter from './Counter.svelte'
provideStoreon(store)
</script>
<Counter />
Import useStoreon
function from our @storeon/svelte
module and use it for getting state and dispatching new events:
Child.svelte
<script>
import { useStoreon } from '@storeon/svelte';
const { count, dispatch } = useStoreon('count');
function increment() {
dispatch('inc');
}
</script>
<h1>The count is {$count}</h1>
<button on:click={increment}>+</button>
Using typescript you can pass State
and Events
interfaces to useStoreon
function to be full type safe
<script lang="typescript">
import { useStoreon } from '@storeon/svelte';
import { State, Events } from './store'
const { count, dispatch } = useStoreon<State, Events>('count');
function increment() {
dispatch('inc');
}
</script>
<h1>The count is {$count}</h1>
<button on:click={increment}>+</button>
If you want to use the @storeon/svelte with the @storeon/router
you should import the router.createRouter
from @storeon/router
and add this module to createStoreon
store.js
import { createStoreon } from 'storeon'
import { createRouter } from '@storeon/router';
const store = createStoreon([
createRouter([
['/', () => ({ page: 'home' })],
['/blog', () => ({ page: 'blog' })],
])
])
And use it like:
App.svelte
<script>
import { provideStoreon } from '@storeon/svelte'
import { store } from './store'
import Counter from './Child.svelte'
provideStoreon(store)
</script>
<Counter />
Child.svelte
<script>
import { useStoreon } from '@storeon/svelte';
import router from '@storeon/router'
const { [router.key]: route } = useStoreon(router.key)
</script>
You can access the router like default svelte store via $:
{$route.match.page}