Public API Matrix
hummbit
getState(): Readonly<RootState>setState(input: RootState | NextStateUpdater<RootState>): Promise<void>mergeState(input: Patch<RootState> | Updater<RootState>): Promise<void>configureGlobalStore(config: GlobalStoreConfig): voidselector<T>(selectorFn: (state: Readonly<RootState>) => T): TinitStore(config, options?): InitializedStore<...>
hummbit/react
getState(): Readonly<RootState>setState(input: RootState | NextStateUpdater): Promise<void>mergeState(input: Patch | MergeUpdater): Promise<void>useSelector<T>(selectorFn, equalityFn?): TconfigureGlobalStore(config): voidinitStore(config, options?): InitializedReactStore<...>
API Reference
hummbit.getState
Reads a one-time immutable snapshot from the global singleton store.
Example 1: Basic read
import { getState } from "hummbit";
const snapshot = getState();
console.log(snapshot);Example 2: Read nested field safely
import { getState } from "hummbit";
const userName = getState().user?.name ?? "anonymous";Example 3: Event handler read
import { getState } from "hummbit";
function onCheckoutClick() {
const cart = getState().cart;
submitCheckout(cart);
}Example 4: Read after awaited update
import { setState, getState } from "hummbit";
await setState((prev) => ({ ...prev, ready: true }));
console.log(getState().ready); // trueExample 5: Anti-pattern vs correct
import { getState } from "hummbit";
// Anti-pattern: assume this value stays fresh forever
const cached = getState().counter;
// Correct: call getState() each time you need fresh data
const fresh = getState().counter;hummbit.setState
Replaces global root state. Accepts object or updater. Returns Promise<void>.
Example 1: Direct replace object
import { setState } from "hummbit";
await setState({ user: { id: "u1" }, ready: true });Example 2: Replace using updater
import { setState } from "hummbit";
await setState((prev) => ({ ...prev, ready: !prev.ready }));Example 3: Async updater
import { setState } from "hummbit";
await setState(async (prev) => {
const profile = await loadProfile();
return { ...prev, profile };
});Example 4: Ordered updates
import { setState } from "hummbit";
const p1 = setState((s) => ({ ...s, step: 1 }));
const p2 = setState((s) => ({ ...s, step: 2 }));
await Promise.all([p1, p2]); // applied in call orderExample 5: Anti-pattern vs correct
import { setState } from "hummbit";
// Anti-pattern: forget unchanged fields
await setState({ user: { id: "u2" } } as any);
// Correct: preserve root explicitly
await setState((prev) => ({ ...prev, user: { ...prev.user, id: "u2" } }));hummbit.mergeState
Applies shallow root patch. Returns Promise<void>.
Example 1: Root patch
import { mergeState } from "hummbit";
await mergeState({ loading: true });Example 2: Updater patch
import { mergeState } from "hummbit";
await mergeState((prev) => ({ counter: prev.counter + 1 }));Example 3: Async patch
import { mergeState } from "hummbit";
await mergeState(async () => {
const token = await refreshToken();
return { token };
});Example 4: Real-world status machine
import { mergeState } from "hummbit";
await mergeState({ requestStatus: "pending" });
await mergeState({ requestStatus: "done" });Example 5: Anti-pattern vs correct deep update
import { mergeState } from "hummbit";
// Anti-pattern: overwrites full user object
await mergeState({ user: { age: 31 } as any });
// Correct:
await mergeState((prev) => ({ user: { ...prev.user, age: 31 } }));hummbit.configureGlobalStore
Configures global singleton DevTools/middleware behavior.
Example 1: Disable DevTools
import { configureGlobalStore } from "hummbit";
configureGlobalStore({ devtools: false });Example 2: Force-enable with custom name
import { configureGlobalStore } from "hummbit";
configureGlobalStore({ devtools: { enabled: true, name: "app-global" } });Example 3: Add global middleware
import { configureGlobalStore, type Middleware } from "hummbit";
type Root = { count: number };
const logger: Middleware<Root> = (ctx) => ({
afterUpdate: () => console.log("count", ctx.getState().count),
});
configureGlobalStore({ middleware: [logger] });Example 4: Startup initialization
import { configureGlobalStore } from "hummbit";
export function bootstrap() {
configureGlobalStore({ devtools: true });
// call before first setState/mergeState
}Example 5: Anti-pattern vs correct
import { configureGlobalStore } from "hummbit";
// Anti-pattern: configure late during runtime
setTimeout(() => configureGlobalStore({ devtools: false }), 5000);
// Correct: configure once at startup
configureGlobalStore({ devtools: false });hummbit.selector
One-off selector read on global state (non-reactive).
Example 1: Basic read
import { selector } from "hummbit";
const isAuth = selector((s) => Boolean(s.session?.token));Example 2: Derived value
import { selector } from "hummbit";
const total = selector((s) => s.items.reduce((acc, i) => acc + i.price, 0));Example 3: Optional chaining
import { selector } from "hummbit";
const city = selector((s) => s.user?.address?.city ?? "unknown");Example 4: Guard before side effect
import { selector } from "hummbit";
if (selector((s) => s.flags?.canUpload)) {
startUpload();
}Example 5: Anti-pattern vs correct
import { selector } from "hummbit";
// Anti-pattern: treat selector as subscription
const value = selector((s) => s.counter);
// Correct: call again after updates, or in React use useSelector
const next = selector((s) => s.counter);hummbit.initStore
Creates isolated typed store instance with actions, selectors, select.
Example 1: Minimal typed store
import { initStore } from "hummbit";
const store = initStore({
initialState: { count: 0 },
actions: ({ actionCreator, setState }) => ({
inc: actionCreator("inc", () =>
setState((s) => ({ ...s, count: s.count + 1 })),
),
}),
selectors: { count: (s) => s.count },
});Example 2: Using select(...)
const count = store.select(store.selectors.count);Example 3: freeze: false
import { initStore } from "hummbit";
const store = initStore({
initialState: { debug: true },
freeze: false,
actions: () => ({}),
selectors: { debug: (s) => s.debug },
});Example 4: DevTools options (second initStore argument)
import { initStore } from "hummbit";
const store = initStore(
{
initialState: { q: 0 },
devtools: { name: "query-store" },
actions: () => ({}),
selectors: { q: (s) => s.q },
},
{ devtools: { hideSetState: true } },
);Important distinction:
config.devtools(first argument) controls whether DevTools integration is enabled.options.devtools(second argument) controls fine-grained logging/name behavior.- They are separate layers and work together.
Full second-argument shape:
type InitStoreOptions = {
devtools?: {
name?: string;
hideSetState?: boolean;
hideMergeState?: boolean;
};
};Meaning:
options.devtools.name- store instance name shown in Redux DevTools.
This has higher priority thanconfig.devtools.name.options.devtools.hideSetState- hidessetStateentries in DevTools log (does not affect store behavior).options.devtools.hideMergeState- hidesmergeStateentries in DevTools log (does not affect store behavior).
Example 5: Anti-pattern vs correct
// Anti-pattern: giant global module augmentation for everything
// Correct: prefer instance-local typing with initStorehummbit/react.getState
Same semantics as hummbit.getState, but typed through public augmentable RootState.
Example 1: Basic read
import { getState } from "hummbit/react";
const st = getState();Example 2: One-off UI command read
import { getState } from "hummbit/react";
function onOpenModal() {
if (getState().permissions?.canOpen) openModal();
}Example 3: Effect helper
import { getState } from "hummbit/react";
track("page_open", { locale: getState().locale });Example 4: Await then read
import { setState, getState } from "hummbit/react";
await setState((s) => ({ ...s, hydrated: true }));
console.log(getState().hydrated);Example 5: Anti-pattern vs correct
// Anti-pattern: use getState() to drive render continuously
// Correct: for render data use useSelector(...)hummbit/react.setState
Global root replacement from React entrypoint.
Example 1: Toggle boolean
import { setState } from "hummbit/react";
await setState((s) => ({ ...s, open: !s.open }));Example 2: Async fetch integration
import { setState } from "hummbit/react";
await setState(async (s) => ({ ...s, profile: await fetchProfile() }));Example 3: Loading lifecycle
import { setState } from "hummbit/react";
await setState((s) => ({ ...s, loading: true }));
await setState((s) => ({ ...s, loading: false }));Example 4: Event callback update
import { setState } from "hummbit/react";
const onDismiss = () => setState((s) => ({ ...s, toast: null }));Example 5: Anti-pattern vs correct
// Anti-pattern: mutate old state object then return it
// Correct: always return a new root objecthummbit/react.mergeState
Global shallow root merge from React entrypoint.
Example 1: Set loading flag
import { mergeState } from "hummbit/react";
await mergeState({ loading: true });Example 2: Updater patch
import { mergeState } from "hummbit/react";
await mergeState((s) => ({ counter: s.counter + 1 }));Example 3: Async patch
import { mergeState } from "hummbit/react";
await mergeState(async () => ({ token: await refreshToken() }));Example 4: Form wizard
import { mergeState } from "hummbit/react";
await mergeState({ step: 2 });Example 5: Anti-pattern vs correct
// Anti-pattern: expect deep merge of nested object
// Correct: spread nested fields explicitlyhummbit/react.useSelector
Subscribes React component to global singleton state slices.
Example 1: Basic usage
import { useSelector } from "hummbit/react";
function Counter() {
const value = useSelector((s) => s.counter);
return <span>{value}</span>;
}Example 2: Custom equality
import { useSelector } from "hummbit/react";
const id = useSelector(
(s) => s.user.id,
(a, b) => a === b,
);Example 3: Derived selector
import { useSelector } from "hummbit/react";
const total = useSelector((s) => s.items.reduce((acc, i) => acc + i.qty, 0));Example 4: Split selectors for perf
const name = useSelector((s) => s.user.name);
const age = useSelector((s) => s.user.age);Example 5: Anti-pattern vs correct
// Anti-pattern: create unstable object without equality
const userView = useSelector((s) => ({ id: s.user.id, name: s.user.name }));
// Correct: pass equality or select primitives separatelyhummbit/react.configureGlobalStore
Same function exported from React entrypoint for convenience.
Example 1: Disable devtools
import { configureGlobalStore } from "hummbit/react";
configureGlobalStore({ devtools: false });Example 2: Name devtools instance
configureGlobalStore({ devtools: { enabled: true, name: "react-global" } });Example 3: Add middleware
import { configureGlobalStore, type Middleware } from "hummbit/react";
const mw: Middleware<any> = () => ({
afterUpdate: () => console.log("updated"),
});
configureGlobalStore({ middleware: [mw] });Example 4: Boot file setup
export const setupStore = () => {
configureGlobalStore({ devtools: true });
};Example 5: Anti-pattern vs correct
// Anti-pattern: reconfigure repeatedly in components
// Correct: configure once in app bootstraphummbit/react.initStore
Creates store instance and adds store.useSelector.
Example 1: Basic React store
import { initStore } from "hummbit/react";
export const store = initStore({
initialState: { count: 0 },
actions: ({ actionCreator, setState }) => ({
inc: actionCreator("inc", () =>
setState((s) => ({ ...s, count: s.count + 1 })),
),
}),
selectors: { count: (s) => s.count },
});Example 2: Consume with store.useSelector
function Counter() {
const count = store.useSelector(store.selectors.count);
return <button onClick={() => store.actions.inc()}>{count}</button>;
}Example 3: Custom equality in store selector
const profile = store.useSelector(
(s) => s.profile,
(a, b) => a.id === b.id && a.version === b.version,
);Example 4: Async action pattern
const asyncStore = initStore({
initialState: { loading: false, data: null as null | string },
actions: ({ actionCreator, setState }) => ({
load: actionCreator("load", async () => {
await setState((s) => ({ ...s, loading: true }));
const data = await Promise.resolve("ok");
await setState((s) => ({ ...s, loading: false, data }));
}),
}),
selectors: { data: (s) => s.data, loading: (s) => s.loading },
});Example 5: Anti-pattern vs correct
// Anti-pattern: store business logic in component local state only
// Correct: centralize shared domain updates in initStore actions
