Skip to main content

Store and Atom

@vef-framework-react/core provides two state management approaches: Zustand-based stores and Jotai atoms.

Zustand Stores

createStore

Creates a global bound store with subscribeWithSelector and immer middleware.

The state type must include a name: string field.

import { createStore } from "@vef-framework-react/core";

interface CounterState {
name: string;
count: number;
increment: () => void;
reset: () => void;
}

export const useCounterStore = createStore<CounterState>(set => ({
name: "counter",
count: 0,
increment: () => {
set(state => {
state.count += 1;
});
},
reset: () => {
set(state => {
state.count = 0;
});
}
}));

Usage in components:

const count = useCounterStore(state => state.count);
const increment = useCounterStore(state => state.increment);

createPersistedStore

Creates a global store that persists to localStorage or sessionStorage.

import { createPersistedStore } from "@vef-framework-react/core";

interface ThemeState {
colorScheme: "light" | "dark";
setColorScheme: (value: "light" | "dark") => void;
}

export const useThemeStore = createPersistedStore<ThemeState>(
set => ({
colorScheme: "light",
setColorScheme: colorScheme => {
set(state => {
state.colorScheme = colorScheme;
});
}
}),
{
name: "theme",
storage: "local",
selector: state => ({ colorScheme: state.colorScheme })
}
);

PersistenceOptions

OptionTypeDescription
namestringUnique storage key
storage"local" | "session"Storage type (default: "local")
selector(state) => partialSelect which fields to persist

createComponentStore

Creates a component-scoped store backed by React Context. Useful for sharing state within a page or feature without polluting global state.

import { createComponentStore } from "@vef-framework-react/core";

interface PageState {
selectedId?: string;
setSelectedId: (id: string) => void;
}

export const {
StoreProvider: PageStoreProvider,
useStore: usePageStore,
useStoreApi: usePageStoreApi
} = createComponentStore<PageState>("MyPage", set => ({
setSelectedId: id => {
set(state => {
state.selectedId = id;
});
}
}));

Wrap the page with the provider:

<PageStoreProvider>
<MyPage />
</PageStoreProvider>

With initial state:

<PageStoreProvider initialState={{ selectedId: "default" }}>
<MyPage />
</PageStoreProvider>

useDeep and useShallow

Selector comparison helpers for Zustand stores:

import { useDeep, useShallow } from "@vef-framework-react/core";

// Shallow comparison (avoids re-render when object reference changes but values are equal)
const { count, name } = useCounterStore(useShallow(state => ({
count: state.count,
name: state.name
})));

// Deep comparison
const config = useConfigStore(useDeep(state => state.config));

Type Exports

TypeDescription
SliceStateCreator<TState, TSlice, TPersist>State creator type for store slices
UnboundStore<TState>Raw Zustand store without React binding
UseBoundStore<TState>Bound store hook type
UseBoundStoreWithPersist<TState>Bound store hook type with persistence
PersistenceOptions<TState, TSelectedState>Options for createPersistedStore
StoreProviderProps<TInitialState>Props for the component store provider
UseStore<TState>Hook signature for useStore

Jotai Atoms

For lightweight, one-off state that does not need a full store.

atom

import { atom } from "@vef-framework-react/core";

const modalAtom = atom({ open: false, data: null as UserRow | null });
const countAtom = atom(0);

useAtom, useAtomValue, useSetAtom

import { useAtom, useAtomValue, useSetAtom } from "@vef-framework-react/core";

// Read and write
const [modal, setModal] = useAtom(modalAtom);

// Read only
const modal = useAtomValue(modalAtom);

// Write only
const setModal = useSetAtom(modalAtom);

AtomStoreProvider and createAtomStore

For isolated atom scopes:

import { AtomStoreProvider, createAtomStore } from "@vef-framework-react/core";

const store = createAtomStore();

<AtomStoreProvider store={store}>
<IsolatedFeature />
</AtomStoreProvider>

useAtomStore and getDefaultAtomStore

import { useAtomStore, getDefaultAtomStore } from "@vef-framework-react/core";

// Inside component
const store = useAtomStore();

// Outside React
const store = getDefaultAtomStore();
const value = store.get(countAtom);
store.set(countAtom, 1);

Atom Type Exports

TypeDescription
Atom<T>Read-only atom type
PrimitiveAtom<T>Read-write primitive atom type
WritableAtom<T, Args, Result>Writable atom type
AtomGetterGetter function type
AtomSetterSetter function type
ExtractAtomValue<T>Extract value type from atom
ExtractAtomArgs<T>Extract args type from writable atom
ExtractAtomResult<T>Extract result type from writable atom
SetStateAction<T>Set state action type