State Management
Source: docs/guides/state-management.md
State Management
Korporus apps use Zustand for state management. Since both slot components (menubar, main) are loaded from the same MF remote, they share a single JavaScript context and can use the same Zustand store.
Basic Pattern
// src/store.ts
import { create } from "zustand";
interface MyStore {
count: number;
increment: () => void;
}
export const useMyStore = create((set) => ({
count: 0,
increment: () => set((s) => ({ count: s.count + 1 })),
})); Using the Store in Slot Components
// src/components/MyMain.tsx
import { useMyStore } from "../store";
export function MyMain() {
const count = useMyStore((s) => s.count);
const increment = useMyStore((s) => s.increment);
return (
Count: {count}
);
}When MyMain calls increment, the menubar component will also re-render if it subscribes to count.
Why Zustand?
- No provider needed: Unlike React Context, Zustand stores don't require a Provider wrapper. This matters because each slot is a separate React root — they don't share a React tree.
- Shared singleton: Zustand is declared as a shared singleton in the MF config, so all slots use the same store instance.
- Simple API:
create+useStore— no boilerplate.
State Doesn't Persist
By default, Zustand state is in-memory only. When the user navigates away from the app and back, the state resets. If you need persistence, use Zustand's persist middleware with localStorage.
System-Wide Settings
For global appearance settings (mode, theme, motion), use @korporus/system-settings instead of reading local storage directly:
import { readAppearance, subscribeAppearance } from "@korporus/system-settings";
const initialAppearance = readAppearance();
const unsubscribe = subscribeAppearance((next) => {
// update UI based on next.mode / next.theme / next.motion
});