Utility
@ilokesto/state/utils exports small helpers for the parts of state management that are not tied to a framework adapter:
pipecreates an@ilokesto/storeinstance and applies middleware in order.adaptorwraps Immerproduceso object updates can be written with draft mutation syntax.
Use Utility pages when you are building the store before connecting it to React, Vue, Svelte, Solid, or Angular.
Why utilities are separate from adapters
Framework adapters answer “how does this state become reactive in my UI?” Utilities answer “how do I prepare or write the state itself?” That separation lets the same store setup be reused across multiple frameworks or outside UI code.
import { create } from '@ilokesto/state/react';
import { logger, persist } from '@ilokesto/state/middleware';
import { pipe } from '@ilokesto/state/utils';
const preferencesStore = pipe(
{ theme: 'system' as 'system' | 'light' | 'dark' },
persist({ local: 'preferences' }),
logger({ collapsed: true }),
);
export const usePreferences = create(preferencesStore);The component still uses the normal adapter API. The utility layer only prepares the store passed into create.
Installation notes
pipe only needs @ilokesto/state and its dependency on @ilokesto/store.
adaptor uses immer, which is an optional peer dependency. Install it only if you use adaptor.
pnpm add immerChoose the right utility
| Utility | Use it when | Avoid it when |
|---|---|---|
pipe | You want to create a store and apply middleware left-to-right. | You already own a Store<T> and want to mutate that exact instance manually. |
adaptor | Object updates are easier to express as draft mutations. | State is primitive, or you do not want to install immer. |
Typical composition flow
- Define initial state.
- Compose middleware with
pipeif the state needs persistence, logging, validation, debouncing, or DevTools. - Pass the resulting store to a framework adapter’s
create. - Use
adaptorinsidesetStatecalls only where draft syntax improves readability.
import { create } from '@ilokesto/state/react';
import { validate } from '@ilokesto/state/middleware';
import { adaptor, pipe } from '@ilokesto/state/utils';
const profileStore = pipe(
{ name: '', tags: [] as string[] },
validate(profileSchema),
);
const useProfile = create(profileStore);
function AddTagButton({ tag }: { tag: string }) {
const [, setProfile] = useProfile((state) => state.tags);
return (
<button
onClick={() =>
setProfile(adaptor((draft) => {
draft.tags.push(tag);
}))
}
>
Add tag
</button>
);
}Related pages
- Middleware explains the middleware functions that
pipecommonly composes. - Plain state guide shows when
setState-style updates are enough. - Reducer state guide shows when named actions are a better fit.