Quick Start
This page builds a counter store and reads it from a functional component. For class components, see Class Components.
1. Wrap your app in <NekutaStore>
Every store lives on a Nekuta instance — the equivalent of a Pinia instance. <NekutaStore> creates one and makes it available to everything below it, in one step:
import { NekutaStore } from '@devtools/core';
export function App() {
return (
<NekutaStore>
<Counter />
</NekutaStore>
);
}
2. Define a store
import { defineStore } from '@devtools/core';
export const useCounterStore = defineStore({
id: 'counter',
state: () => ({ count: 0 }),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment(this: { count: number }, by = 1) {
this.count += by;
}
}
});
id must be unique across your app — it's the key Nekuta uses to store this store's state on the Nekuta instance. state is a factory function (called once per Nekuta instance) so each instance gets its own fresh copy, never a shared reference.
3. Read and write it from a component
import { useStore } from '@devtools/core';
import { useCounterStore } from './stores/counterStore';
export function Counter() {
const counter = useStore(useCounterStore);
return (
<div>
<p>
{counter.count} (double: {counter.doubleCount})
</p>
<button onClick={() => counter.increment()}>+1</button>
</div>
);
}
useStore() is the hook — it takes the store definition (useCounterStore, what defineStore() returned) and gives you back the live store, subscribed for re-renders. State, getters, and actions are all accessed directly off the object it returns: counter.count, counter.doubleCount, counter.increment().
Mutating state directly also works, the same as Pinia:
<button onClick={() => counter.count++}>+1 (direct mutation)</button>
Next steps
- Class Components — the same store, read via
connectStore()instead. - Defining Stores — the setup-style alternative to the options object above.
- State, Getters, Actions — one page each on the three pieces used above.