React Native Cheatsheet

Storage

Use this React Native reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

AsyncStorage

Simple key-value storage that persists across app restarts. Async, string-only values.

npm install @react-native-async-storage/async-storage
cd ios && pod install

Basic Operations

import AsyncStorage from '@react-native-async-storage/async-storage';

// Set
await AsyncStorage.setItem('user_token', token);
await AsyncStorage.setItem('user', JSON.stringify({ id: 1, name: 'Alice' }));

// Get
const token = await AsyncStorage.getItem('user_token');
const raw = await AsyncStorage.getItem('user');
const user = raw ? JSON.parse(raw) : null;

// Remove
await AsyncStorage.removeItem('user_token');

// Clear all
await AsyncStorage.clear();

// Multi-get / multi-set
const keys = ['@key1', '@key2', '@key3'];
const pairs = await AsyncStorage.multiGet(keys);
// pairs = [['@key1', 'val1'], ['@key2', 'val2'], ...]

await AsyncStorage.multiSet([
  ['@key1', 'value1'],
  ['@key2', 'value2'],
]);

await AsyncStorage.multiRemove(['@key1', '@key2']);

// Get all keys
const allKeys = await AsyncStorage.getAllKeys();

// Merge (deep merge for JSON values)
await AsyncStorage.mergeItem('user', JSON.stringify({ name: 'Bob' }));

Typed AsyncStorage Wrapper

const Storage = {
  async set<T>(key: string, value: T): Promise<void> {
    await AsyncStorage.setItem(key, JSON.stringify(value));
  },

  async get<T>(key: string): Promise<T | null> {
    const raw = await AsyncStorage.getItem(key);
    return raw ? (JSON.parse(raw) as T) : null;
  },

  async remove(key: string): Promise<void> {
    await AsyncStorage.removeItem(key);
  },
};

// Usage
await Storage.set('session', { token: 'abc', expiresAt: Date.now() + 3600000 });
const session = await Storage.get<{ token: string; expiresAt: number }>('session');

MMKV (High-performance alternative)

Synchronous, C++ native, ~30× faster than AsyncStorage.

npm install react-native-mmkv
cd ios && pod install
import { MMKV } from 'react-native-mmkv';

const storage = new MMKV();

// Synchronous — no await
storage.set('user.id', 42);
storage.set('user.name', 'Alice');
storage.set('user.active', true);
storage.set('token', 'abc123');

const id = storage.getNumber('user.id');        // number | undefined
const name = storage.getString('user.name');    // string | undefined
const active = storage.getBoolean('user.active'); // boolean | undefined

storage.delete('token');
storage.clearAll();

const keys = storage.getAllKeys();

// Encrypted storage
const secureStorage = new MMKV({ id: 'secure', encryptionKey: 'my-key' });

// JSON values
storage.set('user', JSON.stringify({ id: 1, name: 'Alice' }));
const user = JSON.parse(storage.getString('user') ?? 'null');

// Listen to changes
storage.addOnValueChangedListener((changedKey) => {
  console.log('Changed:', changedKey, storage.getString(changedKey));
});

MMKV with Zustand (persist middleware)

import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { MMKV } from 'react-native-mmkv';

const storage = new MMKV();

const mmkvStorage = {
  setItem: (name: string, value: string) => storage.set(name, value),
  getItem: (name: string) => storage.getString(name) ?? null,
  removeItem: (name: string) => storage.delete(name),
};

const useStore = create(
  persist(
    (set) => ({ count: 0, increment: () => set(s => ({ count: s.count + 1 })) }),
    { name: 'app-store', storage: createJSONStorage(() => mmkvStorage) }
  )
);

Expo SecureStore (Keychain / Keystore)

Encrypted storage backed by iOS Keychain and Android Keystore.

npx expo install expo-secure-store
import * as SecureStore from 'expo-secure-store';

// Save
await SecureStore.setItemAsync('auth_token', token);
await SecureStore.setItemAsync('private_key', key, {
  keychainAccessible: SecureStore.WHEN_UNLOCKED,
  // Options: ALWAYS | WHEN_UNLOCKED | AFTER_FIRST_UNLOCK | ALWAYS_THIS_DEVICE_ONLY | WHEN_UNLOCKED_THIS_DEVICE_ONLY
});

// Get
const token = await SecureStore.getItemAsync('auth_token');

// Delete
await SecureStore.deleteItemAsync('auth_token');

// Synchronous (Expo SDK 48+)
SecureStore.setItem('key', 'value');
const value = SecureStore.getItem('key');

Keychain (RN CLI — react-native-keychain)

npm install react-native-keychain
cd ios && pod install
import * as Keychain from 'react-native-keychain';

// Save credentials (username + password pair)
await Keychain.setGenericPassword('alice@example.com', 'secret123');

// Retrieve
const credentials = await Keychain.getGenericPassword();
if (credentials) {
  console.log(credentials.username);
  console.log(credentials.password);
}

// Reset
await Keychain.resetGenericPassword();

// With biometric protection
await Keychain.setGenericPassword('user', token, {
  accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_ANY,
  accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED,
});

SQLite

For relational/structured local data with queries.

# Expo
npx expo install expo-sqlite

# RN CLI
npm install react-native-sqlite-storage

expo-sqlite (v14+, async API)

import * as SQLite from 'expo-sqlite';

// Open database
const db = await SQLite.openDatabaseAsync('mydb.db');

// Execute DDL
await db.execAsync(`
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL
  );
`);

// Insert
const result = await db.runAsync(
  'INSERT INTO users (name, email) VALUES (?, ?)',
  ['Alice', 'alice@example.com']
);
console.log(result.lastInsertRowId);
console.log(result.changes);

// Select all
const rows = await db.getAllAsync<{ id: number; name: string; email: string }>(
  'SELECT * FROM users'
);

// Select first row
const user = await db.getFirstAsync<{ id: number }>(
  'SELECT * FROM users WHERE email = ?',
  ['alice@example.com']
);

// Async iterator (large result sets)
for await (const row of db.getEachAsync('SELECT * FROM users')) {
  process(row);
}

// Transaction
await db.withTransactionAsync(async () => {
  await db.runAsync('INSERT INTO users (name, email) VALUES (?, ?)', ['Bob', 'bob@ex.com']);
  await db.runAsync('INSERT INTO users (name, email) VALUES (?, ?)', ['Carol', 'carol@ex.com']);
});

// Close
await db.closeAsync();

Drizzle ORM with SQLite (type-safe)

npm install drizzle-orm expo-sqlite
npm install -D drizzle-kit
import { drizzle } from 'drizzle-orm/expo-sqlite';
import { openDatabaseSync } from 'expo-sqlite';
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
import { eq } from 'drizzle-orm';

const usersTable = sqliteTable('users', {
  id: integer('id').primaryKey({ autoIncrement: true }),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
});

const expo = openDatabaseSync('db.db');
const db = drizzle(expo, { schema: { usersTable } });

// Insert
await db.insert(usersTable).values({ name: 'Alice', email: 'alice@ex.com' });

// Select
const users = await db.select().from(usersTable);
const alice = await db.select().from(usersTable).where(eq(usersTable.email, 'alice@ex.com'));

// Update
await db.update(usersTable).set({ name: 'Alicia' }).where(eq(usersTable.id, 1));

// Delete
await db.delete(usersTable).where(eq(usersTable.id, 1));

React Native File System

npx expo install expo-file-system
# or
npm install react-native-fs

expo-file-system

import * as FileSystem from 'expo-file-system';

const dir = FileSystem.documentDirectory;  // app private directory

// Write
await FileSystem.writeAsStringAsync(`${dir}notes.txt`, 'Hello World');

// Read
const content = await FileSystem.readAsStringAsync(`${dir}notes.txt`);

// Download file
const { uri } = await FileSystem.downloadAsync(
  'https://example.com/file.pdf',
  `${dir}file.pdf`,
  { headers: { Authorization: `Bearer ${token}` } }
);

// File info
const info = await FileSystem.getInfoAsync(`${dir}notes.txt`);
info.exists;  info.size;  info.modificationTime;

// Delete
await FileSystem.deleteAsync(`${dir}notes.txt`);

// Directory listing
const files = await FileSystem.readDirectoryAsync(dir);

// Move / Copy
await FileSystem.moveAsync({ from: srcUri, to: destUri });
await FileSystem.copyAsync({ from: srcUri, to: destUri });

// Directories
await FileSystem.makeDirectoryAsync(`${dir}images`, { intermediates: true });

Storage locations

LocationExpoNotes
App privateFileSystem.documentDirectoryPersists, backed up (iOS)
CacheFileSystem.cacheDirectoryMay be purged by OS
External (Android)MediaLibraryPublic photos/videos

Redux Persist (state hydration from storage)

npm install redux-persist @reduxjs/toolkit react-redux
import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';

const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  whitelist: ['auth', 'settings'],   // only persist these slices
  blacklist: ['ui'],                  // never persist these
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = configureStore({ reducer: persistedReducer });
export const persistor = persistStore(store);

// In App.tsx
import { PersistGate } from 'redux-persist/integration/react';

<Provider store={store}>
  <PersistGate loading={<ActivityIndicator />} persistor={persistor}>
    <App />
  </PersistGate>
</Provider>

Gotcha: AsyncStorage has a default max item size of ~2 MB and a total storage limit around 6 MB on older Android. Use MMKV or SQLite for large datasets.