Essential Libraries Best Practices
A condensed summary of the 25 most important essential-library practices for Expo SDK 57 mobile teams - drawn from every page in this section.
Search across all documentation pages
A condensed summary of the 25 most important essential-library practices for Expo SDK 57 mobile teams - drawn from every page in this section.
npx expo install for native modules: react-native-reanimated, react-native-gesture-handler, react-native-mmkv, @shopify/flash-list, and @sentry/react-native must match the SDK 57 compatibility table - manual npm pins cause EAS native build failures.
Audit native transitive deps before adopting: Every native library is autolinking surface, install size, and an SDK upgrade reconciliation item - run npx expo-doctor and npx expo prebuild --dry-run on dependency PRs.
TanStack Query owns server state: API lists, profiles, and settings with loading/error/cache belong in Query - not Zustand, Context, or useEffect fetches - @tanstack/react-query.
Zustand owns client UI state: Cart badges, theme prefs, onboarding flags, and filter chips - one store per domain with selectors - zustand.
Never duplicate API data in global stores: If Query already caches products, do not mirror them in Zustand - invalidation becomes manual and logout cleanup fails.
Wire mobile Query lifecycle at bootstrap: onlineManager + NetInfo and focusManager + AppState in _layout - without this, foreground refetch and offline retry behave like web defaults - TanStack Query.
One QueryClient per app: Create in root layout with useState(createQueryClient) - never per screen or per navigator.
Zustand selectors always: useStore((s) => s.field) - bare useStore() re-renders on every slice change.
Secrets never in Zustand persist or MMKV plaintext: Tokens and refresh credentials live in expo-secure-store - MMKV holds non-secret prefs and drafts only.
Pick storage by data shape: AsyncStorage for small JSON at boot; MMKV for synchronous hot-path reads; SQLite for relational offline data - not one store for everything - react-native-mmkv.
Version every persisted schema: meta:schemaVersion for MMKV, PRAGMA user_version for SQLite, keyed migrations before new shapes reach production.
FlashList after profiling, not by default: Migrate feeds when Android profiling shows scroll jank - keep FlatList for short settings screens - @shopify/flash-list.
estimatedItemSize is mandatory on FlashList: Wrong estimates cause scroll jump and blank gaps - set minHeight on rows to match.
Memoize recycled list rows: memo on row components, stable renderItem via useCallback, props-only state - recycled views expose stale closure bugs.
Install Reanimated and Gesture Handler as a pair: SDK 57 matrix - react-native-reanimated ~4.0.0 and react-native-gesture-handler ~2.28.0 - react-native-reanimated & gesture-handler.
Babel plugin last: react-native-reanimated/plugin is always the final entry in babel.config.js - then npx expo start --clear.
GestureHandlerRootView at root: Wrap app/_layout.tsx - pans and sheets fail silently without it.
Import Animated from Reanimated for worklets: Not from react-native - mixing APIs breaks gesture-driven UI.
Rebuild dev client after native library changes: MMKV, FlashList, Sentry, and Reanimated require EAS or dev client rebuild - Metro restart alone is not enough.
One crash reporter: @sentry/react-native with wizard setup - not sentry-expo (deprecated) and not two vendors - sentry-expo / @sentry/react-native.
Sentry.init before other imports: Top of _layout.tsx; Sentry.wrap on root once - pair with source map upload on every EAS production build.
Set release and dist correctly: release = native version + build; dist = OTA update id - aligns crash reports with the binary users run - Sentry for React Native.
Sunset unused libraries before SDK upgrades: Run npx knip and npx depcheck - dead native modules inflate autolinking and break reconciliation - Essential Libraries Basics.
Dependency PR checklist: npx expo install, expo-doctor clean, device test note, no duplicate problem-class library, ADR updated if team default changes.
Logout clears all layers: queryClient.clear(), Zustand reset, MMKV user instance wipe, SecureStore token delete, and SQLite user tables - stale cache is a security defect.
TanStack Query + NetInfo, Zustand, MMKV (when profiled), FlashList (for feeds), Reanimated 4 + Gesture Handler, and @sentry/react-native - installed via npx expo install.
JS-only: @tanstack/react-query, zustand. Native modules: always npx expo install. Commit lockfile changes with every dependency PR.
Start with AsyncStorage. Add MMKV when profiling shows async getItem on the critical path - composer drafts, feature flags read every mount, Zustand persist flicker.
No - profile first. Short lists and settings screens stay on FlatList until scroll performance fails on target Android hardware.
State Management and Observability sections have full cookbooks - Essential Libraries pages are the install-and-defaults cards with links inward.
Stack versions: This page was written for React 19.2.3, React Native 0.86.0, and Expo SDK 57 (
expo~57.0.4).
Reviewed by Chris St. John·Last updated Jul 19, 2026