Wanna grow your state like a pro? 🌱 You've come to the right forest.
Welcome to Bonsai — the chill, lightweight state manager that won't make your brain wilt. Whether you're nurturing a small shrub of global state or a whole enchanted forest of nested components, Bonsai's got you.
Think of it as your Zen garden for state. You get flat and tree-based state tools that make your React life peaceful and performant.
useSyncExternalStore
keeps re-renders minimal.Works perfectly in both client and server components. Hydration? Handled. Transitions? Smooth like butter.
What’s new in v1.1.0
{ devtools, middleware }
devtools: true
; toggle with Ctrl+Shift+B
(next) => (path, value, prev) => next(path, value)
initTreeState
, useTreeBonsai
, set
, subscribe
)npm install @bonsai-ts/state
yarn add @bonsai-ts/state
pnpm add @bonsai-ts/state
bun add @bonsai-ts/state
"use client";
import { createStore } from "@bonsai-ts/state";
// Initialize once with options (auto-mount DevTools in dev when enabled)
export const appStore = createStore(
{
count: 0,
user: { name: "elorm", isActive: true },
},
{ devtools: true }
);
// Use in client components
function Counter() {
const count = appStore.use<number>("count") || 0;
return (
<button onClick={() => appStore.set("count", count + 1)}>
Increment ({count})
</button>
);
}
With createStore
, the APIs are isomorphic. Define your store in a module and use it from client components. DevTools auto-mount only runs in the browser.
// store.ts
import { createStore } from "@bonsai-ts/state";
export const appStore = createStore({ count: 0 }, { devtools: true });
// app/Counter.tsx (Client Component)
"use client";
import { appStore } from "./store";
export function Counter() {
const count = appStore.use<number>("count") || 0;
return <button onClick={() => appStore.set("count", count + 1)}>{count}</button>;
}
// app/page.tsx (Server Component)
import { Counter } from "./Counter";
export default function Page() {
return <Counter />;
}