Counter
The hello world. One store, one component, the whole reactive loop in ~25 lines.
import { createStore, useStore, Store } from "@priolo/jon"
const counterStore = createStore({
state: {
count: 0,
},
actions: {
increment: (_: void, store: Store) => {
store.setCount(store.state.count + 1)
},
},
mutators: {
setCount: (count: number) => ({ count }),
},
})
export default function App() {
// subscribe: every count change re-renders the component
const { count } = useStore(counterStore)
return (
<div>
<button onClick={() => counterStore.increment()}>increment</button>
<p>count: {count}</p>
</div>
)
}
What's going on
useStore(counterStore)subscribes the component and returns the current state. When the state changes, the component re-renders. That's it.- The action
incrementorchestrates: it reads the current state and calls a mutator. Thestorehandle is its second argument — treat it likethis. - The mutator
setCountis the only thing that changes state. It returns a partial state ({ count }) that gets shallow-merged into the store. - You call methods directly on the store, passing only the payload:
counterStore.increment(),counterStore.setCount(5). Everything is typed by inference — no interfaces written anywhere.
Full source: src/examples/counter
Live demo: open on CodeSandbox