Derived
Atomic state manager library inspired by simplicity of Jotai and Svelte stores.
Installation
yarn add @postrockreverb/derived
npm install @postrockreverb/derived
bun add @postrockreverb/derived
Usage
Store
Observable value with get, set, update and subscribe methods.
Counter: 1
import { store, type ObservableType } from '@postrockreverb/derived';import { useSyncExternalStore } from 'react';
// Create a custom hook that takes an ObservableType<T> store object// This hook uses useSyncExternalStore to subscribe to changes in the store and get its current valuefunction use<T>(store: ObservableType<T>, getServerSnapshot?: () => T) { return useSyncExternalStore(store.subscribe, store.get, getServerSnapshot);}
// Create a store with an initial value of 1// Variables for stores are prefixed with $, indicating that it's a storeconst $counter = store(1);
// Stores can be modified outside of componentsfunction add1() { $counter.update((value) => value + 1);}
export default function () { // Use the custom hook use to get the current counter value from the store const counter = use($counter, () => 1);
return ( <p> <button onClick={add1}>Add 1</button>
{/* Stores can also be modified inside components */} <button onClick={() => $counter.update((value) => value + 2)}>Add 2</button>
<span>Counter: {counter}</span> </p> );}
Derived
Derived observable value based on a getter function. It subscribes to stores and updates its value when any of the stores change.
Counter: 1Doubled: 2
import { store, derived, type ObservableType } from '@postrockreverb/derived';import { useSyncExternalStore } from 'react';
function use<T>(store: ObservableType<T>, getServerSnapshot?: () => T) { return useSyncExternalStore(store.subscribe, store.get, getServerSnapshot);}
const $counter = store(1);
// Create a derived store $doubled that computes its value based on the $counter store// Whenever $counter value is changed, the value of $doubled is reevaluatedconst $doubled = derived((get) => { return get($counter) * 2;});
export default function () { const counter = use($counter, () => 1); const doubled = use($doubled, () => 2);
return ( <p> <button onClick={() => $counter.update((value) => value + 1)}>Add 1</button> <span>Counter: {counter}</span> <span>Doubled: {doubled}</span> </p> );}
Contributing
If you would like to contribute to the project, please fork the repository and submit a pull request with your changes.
Contact
If you have any questions or suggestions, feel free to reach out through GitHub Issues.