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 by using setClone
should you have the need to clone more complex data types. See below for an example using klona/full
.
import { store, setClone } from 'vyce';
import { klona } from 'klona/full';
setClone(klona);
const state = store({ name: 'denam' });
API
store(value?)
import { store } from 'vyce';
const state = store({ name: 'denam' });
// call your store without arguments to get the 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 by using 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