Quick Start
From zero to productive in 2 minutes
Install it
npm install zenboxYour first store
Let's build a simple counter. Here's the entire thing:
import { createStore, useStore } from "zenbox";
// Create the store - types are inferred automatically
const counter = createStore({
  count: 0,
  increment: () =>
    counter.setState((s) => {
      s.count++;
    }),
  decrement: () =>
    counter.setState((s) => {
      s.count--;
    }),
  reset: () => counter.setState({ count: 0 }),
});
// Use it in a component
function Counter() {
  const { count, increment, decrement, reset } = useStore(counter);
  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}That's it. No interfaces, no providers, no setup. It just works.
Add some Vue magic
Now let's add computed values and watchers:
import { useComputed, useWatch } from "zenbox";
function EnhancedCounter() {
  // Computed values - update automatically when dependencies change
  const doubled = useComputed(() => counter.value.count * 2);
  const isEven = useComputed(() => counter.value.count % 2 === 0);
  // Watch for changes
  useWatch(
    () => counter.value.count,
    (newCount, oldCount) => {
      if (newCount > 10) {
        console.log("Getting high!");
      }
    }
  );
  return (
    <div>
      <p>Doubled: {doubled}</p>
      <p>Is even: {isEven ? "Yes" : "No"}</p>
      <button onClick={counter.value.increment}>Increment</button>
    </div>
  );
}Multiple stores? No problem
const user = createStore({
  name: "Alice",
  email: "alice@example.com",
});
const posts = createStore({
  items: [],
  addPost: (title) =>
    posts.setState((s) => {
      s.items.push({ id: Date.now(), title, author: user.value.name });
    }),
});
function Summary() {
  // Compute across stores - ZenBox tracks dependencies automatically
  const userSummary = useComputed(
    () => `${user.value.name} has written ${posts.value.items.length} posts`
  );
  return <p>Summary: {userSummary}</p>;
}Optimize re-renders with selectors
When your component only depends on specific fields from the store, use selectors to prevent unnecessary re-renders.
// ❌ Re-renders on any store change, even if age changes
const { name, email, age } = useStore(userStore);
// ✅ Only re-renders when name or email changes
const { name, email } = useStore(userStore, { pick: ["name", "email"] });For convenience, use usePick as a shortcut for selecting specific fields:
// Same as above, but more concise
const { name, email } = usePick(userStore, "name", "email");That's really it
You now know everything you need to be productive with ZenBox:
createStore()for your stateuseStore()to subscribe to state changesusePick()to optimize re-rendersuseComputed()for derived valuesuseWatch()to react to changes
The rest is just building your app. Check out the other guides for advanced patterns.