Skip to content

t1k:rn:base:state-management

FieldValue
Modulebase
Version1.7.4
Effortmedium
Tools

Keywords: async storage, jotai, MMKV, react native, state management, zustand

/t1k:rn:base:state-management

store/useAuthStore.ts
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';
interface AuthState {
token: string | null;
user: User | null;
setToken: (token: string) => void;
logout: () => void;
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
token: null,
user: null,
setToken: (token) => set({ token }),
logout: () => set({ token: null, user: null }),
}),
{
name: 'auth-storage',
storage: createJSONStorage(() => AsyncStorage),
}
)
);

MMKV (Preferred over AsyncStorage for sync access)

Section titled “MMKV (Preferred over AsyncStorage for sync access)”
store/storage.ts
import { MMKV } from 'react-native-mmkv';
export const storage = new MMKV();
// Zustand with MMKV
const mmkvStorage = {
getItem: (name: string) => storage.getString(name) ?? null,
setItem: (name: string, value: string) => storage.set(name, value),
removeItem: (name: string) => storage.delete(name),
};
atoms/themeAtom.ts
import { atom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';
export const themeAtom = atomWithStorage<'light' | 'dark'>('theme', 'light');
export const derivedAtom = atom((get) => get(themeAtom) === 'dark');
// Only re-renders when token changes, not entire store
const token = useAuthStore((state) => state.token);
const logout = useAuthStore((state) => state.logout);
  • Use selectors — never useStore() without selector (subscribes to entire store)
  • MMKV for sync reads (settings, preferences) — AsyncStorage for async-only (large data)
  • Separate UI state (local useState) from app state (Zustand/Jotai)
  • Zustand for global app state, Jotai for atomic reactive state
  • persist middleware hydration is async — check useAuthStore.persist.hasHydrated() before rendering
  • MMKV is not available in Expo Go — requires dev build (eas build --profile development)
  • atomWithStorage from jotai/utils handles hydration automatically
  • Avoid storing sensitive data in AsyncStorage unencrypted — use expo-secure-store
  • Tokens → expo-secure-store (encrypted), not AsyncStorage
  • MMKV data is not encrypted by default — use encryptionKey option for sensitive data
  • Never log store state containing tokens or PII