Store
Overview

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(initialValue) and store.state(initialValue) 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.