ReadyNative

SWR

Set up SWR for data in an Expo app with ReadyNative: stale-while-revalidate hooks · Expo Go OK

Expo Go: yes

Runs in Expo Go; no dev build needed for this module.

SWR is the small data layer: a stale-while-revalidate cache with a global fetcher, configured in src/lib/swr.tsx. I'd pick it over react-query when you mostly read data and want the smallest possible API surface - a string key is all a hook needs - and over apollo whenever your backend isn't GraphQL. It ships the same src/lib/api/client.ts (fetchJson) as the TanStack Query module, so switching between the two doesn't churn your API code.

Setup

bun run setup --data swr
  1. Put your API base URL in .env as EXPO_PUBLIC_API_URL, for example https://jsonplaceholder.typicode.com. It's optional - the example hook stays paused until you set it.

Setup adds src/lib/swr.tsx (SwrProvider, order 20: SWRConfig with fetchJson as the global fetcher, a per-session Map cache, revalidate-on-foreground wired to AppState through isVisible / initFocus, one retry, 2s dedupe), src/lib/api/client.ts and two tests, plus src/hooks/use-example-query.ts and the /examples/query route and screen with --with-examples.

KeyRequiredWhat it is
EXPO_PUBLIC_API_URLnoBase URL that relative fetchJson paths resolve against

Usage

With the global fetcher, a string key is a path relative to EXPO_PUBLIC_API_URL:

const { data, error, isLoading, mutate } = useSWR<Me>("/me");

Pass your own fetcher when you want the types inline, and pass null as the key to pause a request:

const q = useSWR(userId ? `/users/${userId}` : null, (path) => fetchJson<User>(path));

Mutations come from swr/mutation:

const { trigger } = useSWRMutation("/notes", (key, { arg }: { arg: Draft }) =>
  fetchJson<Note>(key, { method: "POST", json: arg })
);

Gotchas

  • Expo Go works - it's pure JS.
  • On every sign-out and account deletion wipeLocalData() runs the onWipeLocalData hooks, and SwrProvider registers mutate(() => true, undefined, { revalidate: false }) there (the mutate bound to its cache), so the next user never sees the previous user's cached responses. If you persist the cache, clear the persisted copy in the same hook.
  • The cache is in memory (createSwrCache). To keep it across launches, back the provider with @/lib/storage: hydrate a Map on start and write it back when AppState goes to background. SWR's "Cache provider" docs cover the shape.
  • isOnline / initReconnect are the library defaults, which means "always online". Add @react-native-community/netinfo and set both in swrConfig for offline-aware revalidation.
  • Swapping stacks: bun run setup --data none (or --data react-query / --data apollo) removes the files, dependency, provider and env key, and with the examples, /examples/query falls back to the core "Module not installed" screen.

Remove it

While modules/ exists (a tree set up with --keep-modules), setup does all of it:

bun run setup --data none --yes --keep-modules

In a finalized tree setup is a stub, so you undo it by hand. Here is everything this module added:

  1. Delete the files that are still there (the demo screens are gone already unless you set up with --with-examples): src/app/examples/query.tsx, src/hooks/__tests__/use-example-query.test.tsx, src/hooks/use-example-query.ts, src/lib/api/__tests__/client.test.ts, src/lib/api/client.ts, src/lib/swr.tsx, src/screens/examples/query-example-screen.tsx.
  2. Replace, don't delete src/hooks/use-forecast.ts: core code imports it, so swap in the no-op version from modules/data/none/files/ of a fresh clone of your tier repo - same exports, nothing behind them.
  3. Uninstall the dependencies: bun remove swr.
  4. Unwrap the provider: delete <SwrProvider> and its import from src/providers.tsx.
  5. Remove the env keys EXPO_PUBLIC_API_URL from .env, .env.example and your EAS environment, and EXPO_PUBLIC_API_URL from src/lib/env.ts.
  6. Check it: bun run typecheck and bun run lint point at anything that still imports the removed files; bun run gen:graph refreshes docs/ARCHITECTURE.md.

Reference

Everything below is generated from modules/data/swr/module.json - the same file bun run setup reads, so it is what actually lands in your repo.

Install

bun run setup --data swr

Module id: data/swr.

Dependencies

PackageVersionKind
swr^2.3.0dependency

Environment keys

KeyRequiredServer-onlyExampleDocs
EXPO_PUBLIC_API_URLnonohttps://jsonplaceholder.typicode.com-

Keys go in .env (see .env.example). Required keys are checked by bun run doctor; Server-only keys have no EXPO_PUBLIC_ prefix, are read only by API routes and never reach the bundle.

Providers

Rendered in src/providers.tsx (lower order = outermost):

OrderProviderFrom
20SwrProvider@/lib/swr

Files

8 files copied to the project root
  • src/app/examples/query.tsx
  • src/hooks/__tests__/use-example-query.test.tsx
  • src/hooks/use-example-query.ts
  • src/hooks/use-forecast.ts
  • src/lib/api/__tests__/client.test.ts
  • src/lib/api/client.ts
  • src/lib/swr.tsx
  • src/screens/examples/query-example-screen.tsx

On this page

Get ReadyNative