Skip to content

State Management

The app uses Zustand for state management with persistence via expo-secure-store.

Auth Store

The primary store handles authentication state.

Location

stores/authStore.ts

State Shape

typescript
interface AuthState {
	// Auth
	user: User | null
	session: Session | null
	isAuthenticated: boolean
	isLoading: boolean

	// Onboarding
	onboardingStep: number
	onboardingData: OnboardingData

	// Actions
	signIn: (email: string) => Promise<void>
	verifyMagicLink: (token: string) => Promise<void>
	signOut: () => Promise<void>
	setOnboardingStep: (step: number) => void
}

Usage

typescript
import { useAuthStore } from "@/stores/authStore"

function ProfileScreen() {
	const { user, signOut } = useAuthStore()

	return (
		<View>
			<Text>{user?.email}</Text>
			<Button onPress={signOut}>Sign Out</Button>
		</View>
	)
}

Selectors

For performance, select only what you need:

typescript
// Good - only re-renders when user changes
const user = useAuthStore((state) => state.user)

// Avoid - re-renders on any state change
const { user, session, isLoading } = useAuthStore()

Persistence

Sensitive data is stored securely:

typescript
import * as SecureStore from "expo-secure-store"

// The store middleware handles persistence
const useAuthStore = create(
	persist(
		(set) => ({
			// state & actions
		}),
		{
			name: "auth-storage",
			storage: createSecureStorage(),
		}
	)
)

Creating New Stores

typescript
import { create } from "zustand"
import { persist } from "zustand/middleware"

interface BookState {
	currentlyReading: Book[]
	addBook: (book: Book) => void
	removeBook: (bookId: string) => void
}

export const useBookStore = create<BookState>()(
	persist(
		(set) => ({
			currentlyReading: [],

			addBook: (book) =>
				set((state) => ({
					currentlyReading: [...state.currentlyReading, book],
				})),

			removeBook: (bookId) =>
				set((state) => ({
					currentlyReading: state.currentlyReading.filter(
						(b) => b.id !== bookId
					),
				})),
		}),
		{
			name: "book-storage",
		}
	)
)

Best Practices

  1. Keep stores focused - One store per domain (auth, books, settings)
  2. Use selectors - Avoid re-renders by selecting specific state
  3. Actions in store - Keep state mutations inside the store
  4. Persist wisely - Only persist necessary data
  5. Secure sensitive data - Use SecureStore for tokens

Built with VitePress