alepha@docs:~/docs/concepts$
cat 9-state-management.md
2 min read
Last commit:

#State Management

Every React developer has been there: Redux boilerplate hell, Context prop drilling nightmares, or Zustand stores that don't survive SSR.

Alepha has a simple state system built around two primitives: $atom for defining state, and $use for consuming it.

#The Problem With Traditional State

In Next.js or Remix, sharing state between server and client is painful:

typescript
1// next.js way - manual serialization, hydration mismatches2export async function getServerSideProps() {3  const user = await getUser();4  return { props: { user } }; // hope it serializes correctly5}

In Redux, you need a store, reducers, actions, and a hydration strategy. That's four files minimum for "I want to share some data."

#Atoms: State Made Simple

An atom is a piece of state with a schema, a name, and optionally a default value.

typescript
 1import { $atom } from "alepha"; 2import { t } from "alepha"; 3  4const userPreferences = $atom({ 5  name: "user.preferences", 6  schema: t.object({ 7    theme: t.enum(["light", "dark"]), 8    language: t.text(), 9    notifications: t.boolean(),10  }),11  default: {12    theme: "light",13    language: "en",14    notifications: true,15  },16});

That's it. No store. No provider. No boilerplate.

#Reading State with $use

In your services, use $use to get the current value:

typescript
1class ThemeService {2  // reactive reference to the atom3  prefs = $use(userPreferences);4 5  isDarkMode() {6    return this.prefs.theme === "dark";7  }8}

In React components, the value updates automatically:

tsx
1const ThemeToggle = () => {2  const prefs = $use(userPreferences);3 4  return (5    <button onClick={() => prefs.theme = prefs.theme === "dark" ? "light" : "dark"}>6      Current: {prefs.theme}7    </button>8  );9};

Yes, you can mutate directly. No action dispatching. No reducers.

#SSR Hydration (It Just Works)

Here's where Alepha shines. Atoms automatically serialize on the server and hydrate on the client.

tsx
1// server: atom value is serialized into HTML2// client: atom hydrates with server value, no flash of wrong content3 4const Dashboard = () => {5  const prefs = $use(userPreferences);6 7  // no hydration mismatch, no loading state8  return <div className={prefs.theme}>...</div>;9};

Compare this to Next.js where you'd need useEffect to avoid hydration errors, or Redux where you manually rehydrate the store.

#Writing State

You can set atom values from anywhere:

typescript
1// direct mutation (in components or services)2prefs.theme = "dark";3 4// or get the alepha instance and use setState5alepha.state(userPreferences, { theme: "dark" });

#Persistence

Atoms can persist to localStorage, cookies, or even Redis:

typescript
1const sessionData = $atom({2  name: "session",3  schema: t.object({4    token: t.optional(t.text()),5    expiresAt: t.optional(t.number()),6  }),7  persist: "localStorage", // survives page refresh8});

Options: "localStorage", "sessionStorage", "cookie", or a custom adapter.

#When To Use Atoms vs Props

Scenario Use
User preferences, theme, language $atom
Authentication state $atom
Page-specific data from resolve Props via $page
Form state useForm hook
Temporary UI state (modal open) useState

Atoms are for global state that multiple components need. Don't atom-ify everything.

#Comparison: Redux vs Jotai vs Alepha

Redux:

typescript
1// store.ts, userSlice.ts, actions.ts, selectors.ts...2// 100+ lines for user preferences3const dispatch = useDispatch();4dispatch(setTheme("dark"));

Jotai:

typescript
1// simpler, but no SSR hydration story2const themeAtom = atom("light");3const [theme, setTheme] = useAtom(themeAtom);

Alepha:

typescript
1// type-safe, SSR-ready, one file2const prefs = $use(userPreferences);3prefs.theme = "dark";

#Advanced: Computed Values

Need derived state? Just compute it:

typescript
1class AppState {2  prefs = $use(userPreferences);3 4  // computed on access, no memoization needed5  get cssClass() {6    return this.prefs.theme === "dark" ? "dark-mode" : "light-mode";7  }8}

#Debugging

Atoms show up in Alepha DevTools (/devtools). You can inspect current values, see which components are subscribed, and even modify state live.

No Redux DevTools extension needed. No setup. It's built in.


State management doesn't have to be complicated. Define your shape with $atom, read it with $use, and let Alepha handle the rest.

On This Page
No headings found...
ready
mainTypeScript
UTF-8concepts_state_management.md