Prompt
Implement a simple note-taking hook using AsyncStorage. Supports: save a note (by key), load a note (by key), delete a note (by key), list all keys.
Solution
AsyncStorage is React Native's plain key-value disk: promise-based, strings only, persisted in the app sandbox (a SQLite database on Android, serialized files on iOS). The community package @react-native-async-storage/async-storage is the living implementation — the core module was deprecated and extracted years ago, and naming the community package is itself a currency signal.
The API surface maps one-to-one onto the hook: setItem/getItem/removeItem/getAllKeys, all async because disk I/O never belongs on the JS thread synchronously. The contracts worth stating: everything is a string, so structured data is JSON.stringify on write and JSON.parse on read — with the parse wrapped in try/catch, because a corrupted or legacy-format entry otherwise crashes the feature that reads it. getItem returns null for missing keys (not an exception). For multi-key screens, multiGet/multiSet batch the native round-trips. And there's no TTL — stale-cache invalidation is your job.
The boundary a senior always draws unprompted: AsyncStorage is plaintext. The OS sandbox is the only barrier, and root, jailbreak, or backup extraction defeats it. Notes, preferences, feature flags, onboarding booleans — yes. Tokens, PII, anything you'd mind leaking — Keychain/Keystore-backed secure storage instead. If reads become hot-path (per-render), the modern escape hatch is MMKV's synchronous JSI storage.
Red flag: "I store the auth token in AsyncStorage — it's inside the app sandbox." Sensitivity decides the storage tier, not convenience.
Say it: "AsyncStorage is an async, string-only, plaintext key-value store — right for non-sensitive state with JSON serialization at the edges, and anything secret goes to Keychain or Keystore instead."