State Management
VEF does not force a single state-management style. Instead, it exposes different tools for different kinds of state:
- Zustand-style stores
- Jotai atoms
- XState state machines
In most projects, the first two are used most often.
Quick Mapping
| Need | Recommended API |
|---|---|
| global application state | createStore() / createPersistedStore() |
| local shared state inside a component tree | createComponentStore() |
| one-off modal or interaction state | atom() |
| complex state transitions | createMachine() |
Global Store: createStore()
import { createStore } from "@vef-framework-react/core";
interface CounterState {
count: number;
increment: () => void;
}
export const useCounterStore = createStore<CounterState>(set => ({
count: 0,
increment: () => {
set(state => {
state.count += 1;
});
}
}));
Persisted Store: createPersistedStore()
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"
}
);
Component-Scoped Store: createComponentStore()
A configuration-page-style setup often looks like this:
import { createComponentStore } from "@vef-framework-react/core";
import { EventEmitter } from "@vef-framework-react/shared";
interface ConfigPageEvents {
submit: undefined;
}
interface ConfigPageState {
eventEmitter: EventEmitter<ConfigPageEvents>;
selectedGroup?: string;
setSelectedGroup: (selectedGroup: string) => void;
}
export const {
StoreProvider: ConfigPageStoreProvider,
useStore: useConfigPageStore
} = createComponentStore<ConfigPageState, never>(
"ConfigPage",
set => ({
eventEmitter: new EventEmitter(),
setSelectedGroup: selectedGroup => {
set(state => {
state.selectedGroup = selectedGroup;
});
}
})
);
Atom State
For single modals, drawers, or local detail state, Jotai is often the lighter option.
import { atom, useAtomValue, useSetAtom } from "@vef-framework-react/core";
const modalAtom = atom({
open: false,
data: null
});
Rule of Thumb
In practice, the order usually looks like this:
- local transient UI state:
useState - local shared state:
atom - page-scoped shared state:
createComponentStore - global shared state:
createStore()/createPersistedStore() - complex process-driven state: state machines