define-store
Define custom stores for reactive programming
Install
Download the CJS, ESM, UMD versions or install via NPM:
npm install @ryanmorr/define-store
Usage
Easily create customizable observable stores that allow you control every aspect of it's behavior and API, including how it's created, how and when it's internal value is read and written, and how subscribers are handled. This allows you to create stores with specific functionality and still maintain interoperability with different reactive libraries.
import defineStore from '@ryanmorr/define-store';
const store = defineStore((get, set, subscribe, subscribers) => {
return (initialValue) => {
set(initialValue);
return {
get,
set(...args) {
set(...args);
},
subscribe(callback) {
const unsubscribe = subscribe(callback);
return {
unsubscribe() {
unsubscribe();
if (subscribers.length === 0) {
}
}
};
}
};
};
});
const value = store(100);
const subscriber = value.subscribe((newValue) => console.log(newValue));
value.get();
value.set(200);
value.get();
subscriber.unsubscribe();
value.toString();
value.valueOf();
value.toJSON();
await value;
Examples
You can make all kinds of different observable stores, for example, here's a basic function-based store:
const store = defineStore((get, set) => (value) => {
set(value);
return (...args) => {
if (args.length === 1) {
set(args[0]);
}
return get();
};
});
const value = store('foo');
const subscribe = value.subscribe((val) => console.log(val));
value();
value('bar');
value();
And how about a computed store to go with it:
const computed = defineStore((get, set) => (deps, callback) => {
const setValue = () => set(callback(deps.map((dep) => dep())));
deps.forEach((dep) => dep.subscribe(setValue));
setValue();
return get;
});
const firstName = store('John');
const lastName = store('Doe');
const fullName = computed([firstName, lastName], ([first, last]) => `${first} ${last}`);
const subscribe = fullName.subscribe((name) => console.log(name));
fullName();
firstName('Jane');
fullName();
lastName('Smith');
fullName();
Or maybe a simple toggle store:
const toggle = defineStore((get, set) => (on = false) => {
set(on);
return {
isOn: get,
on: () => set(true),
off: () => set(false),
toggle: () => set(!get())
};
});
const toggler = toggle();
const subscribe = toggler.subscribe((on) => console.log(on));
toggler.on();
toggler.isOn();
toggler.off();
toggler.isOn();
toggler.toggle();
toggler.isOn();
Don't forget your Redux-style reducer store:
const reduce = defineStore((get, set) => (reducer, initialState) => {
set(initialState);
return {
getState: get,
dispatch: (action) => set(reducer(get(), action))
};
});
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
return state;
}
}
const state = {count: 0};
const counter = reduce(reducer, state);
const subscribe = counter.subscribe((state) => console.log(state));
counter.dispatch({type: 'increment'});
counter.getState();
counter.dispatch({type: 'decrement'});
counter.getState();
License
This project is dedicated to the public domain as described by the Unlicense.