A successful response on a good connection is only one state in a mobile data flow. Users lose connectivity, change filters, retry requests, and encounter failed saves. Expo-data-fetching helps make those states explicit rather than treating them as exceptions around the happy path.
Connect Expo knowledge to your agent
For Codex, run the official Expo plugin command below in a terminal or find Expo through /plugins. For Claude Code, use claude plugin install expo@claude-plugins-official instead. Both plugin installs include Expo Skills and MCP configuration. Other Agent Skills clients can run npx skills@latest add expo/skills --skill '*', choose their client, and refresh the session. Installing the plugin does not itself build or publish an app.
codex plugin add expo@openai-curated
Open the existing Expo project and explicitly request expo-data-fetching, including the SDK version, target platforms, and relevant files.
Extend the existing data layer
Adapt this first request to your project:
Use expo-data-fetching to review the order list and editor. The app already uses React Query and targets iOS/Android. Keep the API, distinguish initial loading, empty results, background refresh errors, and offline states, and preserve edits after failed saves. Prevent duplicate submission, inspect filter-dependent query keys, and explain public configuration versus auth-token storage.
Identify whether the project uses fetch, React Query, or SWR. Supply the endpoint contract, authentication approach, and affected screens. Reuse an existing cache layer where possible. A concrete symptom, such as the list disappearing when refresh fails, provides a better acceptance target than a general request to optimize fetching.
Distinguish missing data from refreshing data
An initial pending request is not an empty result. When cached content exists, a background error may not justify clearing the screen. Define initial loading, empty content, refresh with existing data, and unrecoverable failure separately. Query keys should include parameters that change the result so one filter does not reuse another filter's data incorrectly.
With fetch, check the response status; an HTTP error does not automatically reject the promise. For writes, prevent duplicate submission and retain form input when saving fails. If optimistic updates are appropriate, define rollback and error presentation. Cache duration and retry policies should follow the product's data characteristics rather than a copied example number.
Separate public configuration from credentials
A public API base URL can use an EXPO_PUBLIC_ variable, but its value is embedded in the client bundle. Do not use that mechanism for private keys. Expo requires a statically named process.env property for inlining; dynamic indexing and destructuring are not equivalent. Fully reload the application after changing a local value before diagnosing a stale endpoint as a code failure.
Handle authentication storage and refresh according to the mobile environment. Concurrent expired requests also need a coordinated refresh strategy.
If the agent proposes loader or useLoaderData in a route file, check the target platform and SDK first. Expo Router data loaders currently target web on SDK 55+; native iOS/Android screens should continue using React Query or fetch. For web, inspect web.output in app.json or app.config.js: both server and static require unstable_useServerDataLoaders, while server additionally requires unstable_useServerRendering. A web loader is not a general replacement for a native list screen.
Validate failure paths
Exercise success, empty results, server errors, slow connections, offline behavior, and failed saves. Check for stale results when filters change. The deliverable is a clear state model, bounded request and cache changes, and repeatable checks. The skill cannot make an unreliable API correct, but it can keep the application understandable and recoverable when requests do not succeed.
Test one failure-and-retry journey
Give the agent a repeatable sequence: open an order list, change a filter, and observe whether existing content remains visible or a clear loading state appears. Turn off the network and refresh; show a failure without erasing cached orders. Reconnect, retry, and confirm the same filter is applied. For a save form, enter unsaved notes, simulate a server error, confirm they remain, and retry. Happy-path requests rarely expose the most painful data-loss bug.
With React Query, distinguish first loading from background fetching. A paused query may have no data without actively loading; the interface should explain whether login, connectivity, or initialization is missing. If authentication comes from persistent storage, finish hydration before redirecting. Otherwise cold starts and deep links may briefly land on the wrong screen.
Keep query conditions and cache keys together
If orders are filtered by status, date, and search term, the query key must contain every condition that changes the response. View Pending, switch to Completed, and switch back quickly to look for a flash of the wrong list. Handle cancellation and caching through the project's existing data layer rather than hiding mismatched content. Empty-state copy should distinguish “no orders yet” from “no results for these filters,” so users know whether to create, clear filters, or retry.
Bound uploads that never settle
On a physical iOS device with an Expo SDK 56.0.21 development build, a developer reproduced an expo/fetch upload whose promise stayed pending after a server closed the connection with a truncated response. Set an explicit AbortSignal deadline and distinguish network failure, user cancellation, and incomplete server responses in the UI. If needed, compare the same device with the expo-file-system upload API. This is an Expo API failure case, not proof that every SDK version behaves the same.