t1k:rn:base:state-management
| Field | Value |
|---|---|
| Module | base |
| Version | 1.7.4 |
| Effort | medium |
| Tools | — |
Keywords: async storage, jotai, MMKV, react native, state management, zustand
How to invoke
Section titled “How to invoke”/t1k:rn:base:state-managementRN Base State Management
Section titled “RN Base State Management”Zustand Store Pattern
Section titled “Zustand Store Pattern”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)”import { MMKV } from 'react-native-mmkv';
export const storage = new MMKV();
// Zustand with MMKVconst mmkvStorage = { getItem: (name: string) => storage.getString(name) ?? null, setItem: (name: string, value: string) => storage.set(name, value), removeItem: (name: string) => storage.delete(name),};Jotai Atoms (For fine-grained reactivity)
Section titled “Jotai Atoms (For fine-grained reactivity)”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');Selection Pattern (Prevent over-renders)
Section titled “Selection Pattern (Prevent over-renders)”// Only re-renders when token changes, not entire storeconst token = useAuthStore((state) => state.token);const logout = useAuthStore((state) => state.logout);Key Rules
Section titled “Key Rules”- 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
Gotchas
Section titled “Gotchas”persistmiddleware hydration is async — checkuseAuthStore.persist.hasHydrated()before rendering- MMKV is not available in Expo Go — requires dev build (
eas build --profile development) atomWithStoragefrom jotai/utils handles hydration automatically- Avoid storing sensitive data in AsyncStorage unencrypted — use
expo-secure-store
Security
Section titled “Security”- Tokens →
expo-secure-store(encrypted), not AsyncStorage - MMKV data is not encrypted by default — use
encryptionKeyoption for sensitive data - Never log store state containing tokens or PII