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- Put your API base URL in
.envasEXPO_PUBLIC_API_URL, for examplehttps://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.
| Key | Required | What it is |
|---|---|---|
EXPO_PUBLIC_API_URL | no | Base 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 theonWipeLocalDatahooks, andSwrProviderregistersmutate(() => true, undefined, { revalidate: false })there (themutatebound 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 theproviderwith@/lib/storage: hydrate aMapon start and write it back whenAppStategoes tobackground. SWR's "Cache provider" docs cover the shape. isOnline/initReconnectare the library defaults, which means "always online". Add@react-native-community/netinfoand set both inswrConfigfor 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/queryfalls 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-modulesIn a finalized tree setup is a stub, so you undo it by hand. Here is everything this module added:
- 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. - Replace, don't delete
src/hooks/use-forecast.ts: core code imports it, so swap in the no-op version frommodules/data/none/files/of a fresh clone of your tier repo - same exports, nothing behind them. - Uninstall the dependencies:
bun remove swr. - Unwrap the provider: delete
<SwrProvider>and its import fromsrc/providers.tsx. - Remove the env keys
EXPO_PUBLIC_API_URLfrom.env,.env.exampleand your EAS environment, andEXPO_PUBLIC_API_URLfromsrc/lib/env.ts. - Check it:
bun run typecheckandbun run lintpoint at anything that still imports the removed files;bun run gen:graphrefreshesdocs/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 swrModule id: data/swr.
Dependencies
| Package | Version | Kind |
|---|---|---|
swr | ^2.3.0 | dependency |
Environment keys
| Key | Required | Server-only | Example | Docs |
|---|---|---|---|---|
EXPO_PUBLIC_API_URL | no | no | https://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):
| Order | Provider | From |
|---|---|---|
| 20 | SwrProvider | @/lib/swr |
Files
8 files copied to the project root
src/app/examples/query.tsxsrc/hooks/__tests__/use-example-query.test.tsxsrc/hooks/use-example-query.tssrc/hooks/use-forecast.tssrc/lib/api/__tests__/client.test.tssrc/lib/api/client.tssrc/lib/swr.tsxsrc/screens/examples/query-example-screen.tsx