Counter Example
The classic counter example to understand the basics.
Store Definition
ts
// stores/counterStore.ts
import { store } from "storion/react";
export const counterStore = store({
name: "counter",
state: {
count: 0,
step: 1,
},
setup({ state }) {
return {
increment: () => {
state.count += state.step;
},
decrement: () => {
state.count -= state.step;
},
setStep: (step: number) => {
state.step = step;
},
reset: () => {
state.count = 0;
},
};
},
});Basic Usage
tsx
// components/Counter.tsx
import { useStore } from "storion/react";
import { counterStore } from "../stores/counterStore";
export function Counter() {
const { count, step, increment, decrement, setStep, reset } = useStore(
({ get }) => {
const [state, actions] = get(counterStore);
return {
count: state.count,
step: state.step,
...actions,
};
}
);
return (
<div className="counter">
<h1>{count}</h1>
<div className="controls">
<button onClick={decrement}>-{step}</button>
<button onClick={increment}>+{step}</button>
</div>
<div className="step-control">
<label>Step:</label>
<input
type="number"
value={step}
onChange={(e) => setStep(Number(e.target.value))}
min={1}
/>
</div>
<button onClick={reset}>Reset</button>
</div>
);
}App Setup
tsx
// App.tsx
import { container, StoreProvider } from "storion/react";
import { Counter } from "./components/Counter";
const app = container();
export function App() {
return (
<StoreProvider container={app}>
<Counter />
</StoreProvider>
);
}Single-Store Shorthand
For a standalone counter, use create():
tsx
import { create } from "storion/react";
const [counter, useCounter] = create({
state: { count: 0 },
setup({ state }) {
return {
increment: () => {
state.count++;
},
decrement: () => {
state.count--;
},
};
},
});
function Counter() {
// Selector receives (state, actions, ctx)
// ctx has mixin, scoped, once, etc. - same as useStore
const { count, increment, decrement } = useCounter((state, actions) => ({
count: state.count,
...actions,
}));
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}>+</button>
</div>
);
}
// No StoreProvider needed!Key Takeaways
- Direct mutation works for top-level properties
- useStore selector determines what triggers re-renders
- create() is a shorthand for single-store apps
- Actions are stable references (safe for deps arrays)