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], xs =>
xs.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 passing a second argument to store
should you have the need to clone more complex data types. See below for an example using klona/full
.
import { store } from 'vyce';
import { klona } from 'klona/full';
const state = store({ name: 'denam' }, klona);
API
store()
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
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`
Note that setting a store will only update its value and run subscriptions if the new value is different than the old value. Internally, this is determined by using the ===
operator, which means passing the same reference to an object twice will not trigger an update even if that object has changed properties. In these instances, you can force an update by passing a shallow copy.
import { store } from 'vyce';
const obj = { lanselot: 1 };
const state = store(obj);
const unsub = state.sub(value => console.log(value)); // logs `{ lanselot: 1 }`
obj.warren = 2;
state(obj); // will not log
state({ ...obj }); // logs `{ lanselot: 1, warren: 2 }`
store.end
Calling end
will release all subscriptions and clean up dependency stores, meaning subscriber functions will no longer be called upon updating the store.
import { store, computed } from 'vyce';
const foo = store(10);
const bar = store(20);
const rum = computed([foo, bar], (x, y) => x + y); // 30
const ham = computed([rum, bar], (x, y) => x + y); // 50
rum.end(); // breaks all listeners (ham), and also stops listening to foo and bar
bar(100); // does not affect rum, but *does* affect ham
console.log(rum()); // logs `30`
rum(0); // does not affect ham
console.log(ham()); // logs `130`
Credits
Inspired by flyd, klona, and Svelte Stores.