vyce
A tiny store you can use to build tidy relationships.
import { store, computed } from 'vyce';
const authors = store([
{ name: 'haruki', age: 25 },
{ name: 'james', age: 32 },
{ name: 'agatha', age: 62 }
]);
const youngAuthors = computed(() =>
authors().filter(author => author.age < 40)
);
authors(prev => [
...prev,
{ name: 'david', age: 28 },
{ name: 'lovecraft', age: 57 }
]);
youngAuthors();
// [
// { name: 'haruki', age: 25 },
// { name: 'james', age: 32 },
// { name: 'david', age: 28 }
// ]
Install
Node
npm install vyce
Deno
import { store, computed } from 'https://deno.land/x/vyce/index.js';
Browser
<script src="https://unpkg.com/vyce/dist/vyce.min.js"></script>
In the browser context, the default export name is vyce
.
Browser (ESM)
<script type="module">
import { store, computed } from 'https://unpkg.com/vyce/dist/vyce.js';
</script>
Usage
See index.d.ts for type definitions.
By default, stores created with vyce use a built-in deep clone function adapted from klona. The default function is capable of cloning objects with JSON-valid data types. You may opt to use another deep clone utility across all new stores by initially calling store.setClone
. See below for an example using klona/full
.
import { store } from 'vyce';
import { klona } from 'klona/full';
store.setClone(klona);
// all new stores will now use `klona/full` internally
const state = store({ name: 'denam' });
API
store(value?)
import { store } from 'vyce';
const state = store({ name: 'denam' });
// call your store without arguments to get its value
state(); // `{ name: 'denam' }`
// pass an argument to set its value
state({ age: 18 });
// or pass a function to set a value based on the previous value
state(prev => ({ ...prev, name: 'catiua' }));
state(); // `{ age: 18, name: 'catiua' }`
store.sub
import { store } from 'vyce';
const state = store(10);
const unsub = state.sub(value => console.log(value)); // logs `10`
state(20); // logs `20`
unsub();
state(30); // does not log anything
Setting a store will only update its value and run subscribers if the new value is different than the old value. Internally, this is determined with the !==
operator. Also note: by default, the subscriber function is called once upon subscribing. Pass a falsey value as a second argument to store.sub
to disable the initial call.
import { store } from 'vyce';
const state = store(10);
const unsub = state.sub(value => console.log(value), false); // does not log
state(20); // logs `20`
store.end
Calling end
will detach all subscribers from a store.
import { store, computed } from 'vyce';
const foo = store(10);
const bar = store(20);
const rum = computed(() => foo() + bar()); // 30
const ham = computed(() => rum() + bar()); // 50
const logger = rum.sub(console.log); // logs `30`
rum.end(); // breaks all listeners (ham, logger)
foo(20); // foo updates rum, but since ham is no longer listening to rum, it remains at 50
ham(); // 50
computed
As demonstrated above, you can use computed
to create stores derived from parent stores. Dependencies are tracked automatically. Creation of circular dependencies will throw an error.
import { store, computed } from 'vyce';
const a = store(10);
const b = computed(() => a() + 10);
const c = computed(() => a(b())); // throws `Circular Dependency` Error