why
posting this in reference to https://github.com/aurelia/store/issues/68
how we use aurelia-store
having tried injecting the store and setting up subscriptions manually as well as using the connectTo decorator, we found both methods lacking (boilerplate and too much convention) and decided to dumb it down, this is what we use currently.
it is not perfect but it is contained, somewhat typed and somewhat simple. it does not cover all the edge-cases but so far it works for our use case.
actions
this is an action, both functions are exported for testing-purposes but only the one wrapped in dispatchify is used elsewhere.
export const _addStatistic = (old: State, s: IStatistic) => {
const fn = (n: State) => {
n.statistics.push(s)
}
return produce(old, fn) // produce being immer
}
export const addStatistic = dispatchify(_addStatistic)
dispatchify is pretty much the same as dispatchify from aurelia-store but it registers the action if it’s not registered yet.
using the name property when registering the action isn’t ideal but we have not yet found a use for properly named actions.
export const dispatchify = <T, P extends any[]>(r: Reducer<T, P>) => {
const store: Store<State> = Container.instance.get(Store)
if (!store.isActionRegistered(r as any))
store.registerAction(r.name, r as any)
return (...params: P) => store.dispatch(r as any, ...params)
}
using actions then comes down to importing the dispatchified function and calling it:
import { addStatistic } from 'actions/add-statistic'
await addStatistic({ category: 'what', subcategory: 'ever' })
subscriptions
for subscribing to state changes we use this function:
export const subscribe = <T>(
u: keyof typeof f,
fn: (a: T) => void,
): Subscription => {
const store: Store<State> = Container.instance.get(Store)
return store.state
.pipe(
pluck(...f[u]),
distinctUntilChanged(),
)
.subscribe(fn);
}
where f is an object with keys with names corresponding to properties on the state. this somewhat odd solution was done to have all untyped stuff in one place (as opposed to all the places you call subscribe()). a solution with keyof State would be preferable if you could someohow type sub-properties as well.
const f = {
label: ['label'],
label_coordinate: ['label', 'coordinate'],
}
using subscribe:
import { subscribe, Subscription } from 'state/util'
import { IStatistic } from 'interface/statistic'
export class MyClass {
sub: Subscription
bind() {
this.sub = subscribe<IStatistic[]>(s => {
// updated, typed IStatistic[]
})
}
unbind() {
this.sub.unsubscribe()
}
}