Deft
Ask AI

Search

Search skills, authors and topics

expo / skills

expo-native-ui

Build native-feeling Expo screens: Apple HIG styling, semantic colors, native controls, SF Symbols, media, visual effects, gradients and responsive layout.

Install

npx skills add https://github.com/expo/skills --skill expo-native-ui

Storage

Key-Value Storage

Use the localStorage polyfill for key-value storage. Never use AsyncStorage

tsx
import "expo-sqlite/localStorage/install";
// Simple get/setlocalStorage.setItem("key", "value");localStorage.getItem("key");
// Store objects as JSONlocalStorage.setItem("user", JSON.stringify({ name: "John", id: 1 }));const user = JSON.parse(localStorage.getItem("user") ?? "{}");

When to Use What

Use CaseSolution
Simple key-value (settings, preferences, small data)localStorage polyfill
Large datasets, complex queries, relational dataFull expo-sqlite
Sensitive data (tokens, passwords)expo-secure-store

Storage with React State

Create a storage utility with subscriptions for reactive updates:

tsx
// utils/storage.tsimport "expo-sqlite/localStorage/install";
type Listener = () => void;const listeners = new Map<string, Set<Listener>>();
export const storage = {  get<T>(key: string, defaultValue: T): T {    const value = localStorage.getItem(key);    return value ? JSON.parse(value) : defaultValue;  },
  set<T>(key: string, value: T): void {    localStorage.setItem(key, JSON.stringify(value));    listeners.get(key)?.forEach((fn) => fn());  },
  subscribe(key: string, listener: Listener): () => void {    if (!listeners.has(key)) listeners.set(key, new Set());    listeners.get(key)!.add(listener);    return () => listeners.get(key)?.delete(listener);  },};

React Hook for Storage

tsx
// hooks/use-storage.tsimport { useSyncExternalStore } from "react";import { storage } from "@/utils/storage";
export function useStorage<T>(  key: string,  defaultValue: T): [T, (value: T) => void] {  const value = useSyncExternalStore(    (cb) => storage.subscribe(key, cb),    () => storage.get(key, defaultValue)  );
  return [value, (newValue: T) => storage.set(key, newValue)];}

Usage:

tsx
function Settings() {  const [theme, setTheme] = useStorage("theme", "light");
  return (    <Switch      value={theme === "dark"}      onValueChange={(dark) => setTheme(dark ? "dark" : "light")}    />  );}

Full SQLite for Complex Data

For larger datasets or complex queries, use expo-sqlite directly:

tsx
import * as SQLite from "expo-sqlite";
const db = await SQLite.openDatabaseAsync("app.db");
// Create tableawait db.execAsync(`  CREATE TABLE IF NOT EXISTS events (    id INTEGER PRIMARY KEY AUTOINCREMENT,    title TEXT NOT NULL,    date TEXT NOT NULL,    location TEXT  )`);
// Insertawait db.runAsync("INSERT INTO events (title, date) VALUES (?, ?)", [  "Meeting",  "2024-01-15",]);
// Queryconst events = await db.getAllAsync("SELECT * FROM events WHERE date > ?", [  "2024-01-01",]);