Voltix is a fine-grained state manager for React. You create a store that holds a flat object of keys, and components subscribe to the individual keys they read. Writing one key re-renders only the components reading that key.
npm i @wildgrowth/voltix
react is the only peer dependency, and only the hooks use it. The package is about 5.1 KB gzipped and ships its own types.
react
Without React, import from @wildgrowth/voltix/vanilla. It has every export except the three hooks, and it imports nothing from React:
@wildgrowth/voltix/vanilla
import { createStore } from '@wildgrowth/voltix/vanilla';
Create a store once, at module scope, from an initial state object. It lives outside React: any module can read or write it, and there is no provider to set up.
import { createStore } from '@wildgrowth/voltix'; export const store = createStore({ count: 0, step: 1, });
Every key in the initial object becomes part of the store's typed shape. Reading or writing a key that does not exist is a compile error.
useStoreKey
useStoreKey subscribes to one key and returns its value. The component re-renders only when that key changes.
import { useStoreKey } from '@wildgrowth/voltix'; import { store } from './store'; function Count() { const count = useStoreKey(store, 'count'); return <span>{count}</span>; }
useStoreSelector
For more than one key, useStoreSelector takes an array of keys and returns just those keys. The component re-renders when any of them changes.
import { useStoreSelector } from '@wildgrowth/voltix'; import { store } from './store'; function Status() { const { count, step } = useStoreSelector(store, ['count', 'step']); return <span>{count} (step {step})</span>; }
The selector is always an array: key strings, plus { key: compareFn } entries when a key needs its own comparison. See `useStoreSelector`.
{ key: compareFn }
createStoreHook
createStoreHook binds the store into a hook once, so components stop passing it around. Types are inferred from the store.
import { createStoreHook } from '@wildgrowth/voltix'; import { store } from './store'; export const useCounter = createStoreHook(store); function Controls() { const { count, step } = useCounter(['count', 'step']); return <span>{count} / {step}</span>; }
import { createStore, useStoreKey } from '@wildgrowth/voltix'; const store = createStore({ count: 0 }); function Counter() { const count = useStoreKey(store, 'count'); return ( <div> <button onClick={() => store.increment('count', -1)}>-</button> <span>{count}</span> <button onClick={() => store.increment('count')}>+</button> </div> ); }
increment adds to a numeric key (default amount is 1). The type system allows it only on keys whose value is a number. Writing to the store from an event handler, an effect, or any module updates every subscribed component.
increment
1
select
at