Davstack Store
Intro
Davstack store is a fully-featured, fast and scalable React state management library built on top of Zustand (opens in a new tab).
Features
- ⚡️ Simple API - just define initial state and
.get
/.set
/.use
/.onChange
methods are inferred. - 🧮 Computed Properties and Actions - Define actions and derived state that automatically update when dependent state changes.
- 🚀 Fast - autogenerated nested state selectors make it easy to avoid unnecessary re-renders
- 📈 Scalable - store methods are lazily generated allowing for large comples stores without performance issues
- 🏠 Scoped State - Scope state a subtree of components using
createStoreContext
helper. - 🔄 Immutable Updates - Uses Immer under the hood, allowing you to update state immutably
- 🧩 Extensible - Middlewares and devtools support for easy debugging and extending functionality.
- ✅ TypeScript First - stores are fully typesafe, and all types are inferred.
Installation
npm install @davstack/store
Visit the Davstack Store Docs (opens in a new tab) for more information and examples, such as this todo app example (opens in a new tab).
Demo Usage
Basic example
import { store } from '@davstack/store';
const counterStore = store(0);
function Counter() {
// re-renders when count changes
const count = counterStore.use();
return <div>Count: {count}</div>;
}
function Controls() {
return (
<button onClick={() => counterStore.set(counterStore.get() + 1)}>
Increment
</button>
);
}
// Generated types
const counterStore: StoreApi<number, {}>;
Advanced example
import { store } from '@davstack/store';
const counterStore = store()
.state({ count: 0 })
.actions((store) => ({
increment: () => store.count.set(store.count.get() + 1),
decrement: () => store.count.set(store.count.get() - 1),
}))
.computed((store) => ({
doubleCount: () => store.count.use() * 2,
}))
.effects((store) => ({
logChanges: () => store.onChange(console.log),
}));
function Counter() {
const count = counterStore.count.use();
return <div>Count: {count}</div>;
}
function DoubleCounter() {
const doubleCount = counterStore.doubleCount.use();
return <div>Double Count: {doubleCount}</div>;
}
function Controls() {
return <button onClick={counterStore.increment}>Increment</button>;
}
// Generated types
const counterStore: StoreApi<
{ count: number },
{
increment: () => void;
decrement: () => void;
} & ComputedMethods<{
doubleCount: () => number;
}> & EffectMethods<{
logChanges: () => UnsubscribeFn;
}>;
>;
Note: store(initialState) and store.state(initialState) are equivalent, it's just a matter of preference.
Nested object store example:
- Typesafe
get
/set
/use
/onChange
/assign
methods are generated for all deeply nested state properties. - All methods are generated lazily, so there are no performance issues even with large complex stores.
import { store } from '@davstack/store';
const userStore = store({
name: 'John',
age: 25,
address: {
street: '123 Main St',
city: 'Anytown',
},
});
function UserProfile() {
// only re-renders when name changes
const name = userStore.name.use();
return (
<div>
<p>Name: {name}</p>
</div>
);
}
function AddressForm() {
const userAddress = userStore.address.use();
return (
<form>
<input
value={userAddress.street}
onChange={(e) => userStore.address.street.set(e.target.value)}
/>
<input
value={userAddress.city}
onChange={(e) => userStore.address.city.set(e.target.value)}
/>
</form>
);
}
Visit the Davstack Store Docs (opens in a new tab) for more information and examples.
Acknowledgements
Davstack Store wouldn't be possible without the incredible work done by Daishi Kato (opens in a new tab) and other zustand contributors. We'd also like to give a shout-out to Zustand X (opens in a new tab) for inspiring some of the initial code in this library.
Contributing
Contributions are welcome! Please read our contributing guide for details on our code of conduct and the submission process.
License
This project is licensed under the MIT License. See the LICENSE file for details.