Skip to main content

expo-data-fetching

Framework (OSS). Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, and Expo Router data loaders (`useLoaderData`).

インストールへ移動

ソース情報

リポジトリ
lightconsen/extensions
ソースの最終更新活動
2026年9月8日 12:34
検出された SKILL.md の言語
英語
スター
0
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
7 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
expo-data-fetching
description
Framework (OSS). Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, and Expo Router data loaders (`useLoaderData`).
version
1.0.0
license
MIT
# Expo Networking **You MUST use this skill for ANY networking work including API requests, data fetching, caching, or network debugging.** ## References Consult these resources as needed: ``` references/ expo-router-loaders.md Route-level data loading with Expo Router loaders (web, SDK 55+) offline-and-cancellation.md NetInfo network status, offline-first React Query, AbortController ``` ## When to Use Use this skill when: - Implementing API requests - Setting up data fetching (React Query, SWR) - Using Expo Router data loaders (`useLoaderData`, web SDK 55+) - Debugging network failures - Implementing caching strategies - Handling offline scenarios - Authentication/token management - Configuring API URLs and environment variables ## Preferences - Avoid axios, prefer expo/fetch ## Common Issues & Solutions ### 1. Basic Fetch Usage **Simple GET request**: ```tsx const fetchUser = async (userId: string) => { const response = await fetch(`https://api.example.com/users/${userId}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }; ``` **POST request with body**: ```tsx const createUser = async (userData: UserData) => { const response = await fetch("https://api.example.com/users", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify(userData), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message); } return response.json(); }; ``` --- ### 2. React Query (TanStack Query) **Setup**: ```tsx // app/_layout.tsx import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 1000 * 60 * 5, // 5 minutes retry: 2, }, }, }); export default function RootLayout() { return ( <QueryClientProvider client={queryClient}> <Stack /> </QueryClientProvider> ); } ``` **Fetching data**: ```tsx import { useQuery } from "@tanstack/react-query"; function UserProfile({ userId }: { userId: string }) { const { data, isLoading, error, refetch } = useQuery({ queryKey: ["user", userId], queryFn: () => fetchUser(userId), }); if (isLoading) return <Loading />; if (error) return <Error message={error.message} />; return <Profile user={data} />; } ``` **Mutations**: ```tsx import { useMutation, useQueryClient } from "@tanstack/react-query"; function CreateUserForm() { const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: createUser, onSuccess: () => { // Invalidate and refetch queryClient.invalidateQueries({ queryKey: ["users"] }); }, }); const handleSubmit = (data: UserData) => { mutation.mutate(data); }; return <Form onSubmit={handleSubmit} isLoading={mutation.isPending} />; } ``` --- ### 3. Error Handling **Comprehensive error handling**: ```tsx class ApiError extends Error { constructor(message: string, public status: number, public code?: string) { super(message); this.name = "ApiError"; } } const fetchWithErrorHandling = async (url: string, options?: RequestInit) => { try { const response = await fetch(url, options); if (!response.ok) { const error = await response.json().catch(() => ({})); throw new ApiError( error.message || "Request failed", response.status, error.code ); } return response.json(); } catch (error) { if (error instanceof ApiError) { throw error; } // Network error (no internet, timeout, etc.) throw new ApiError("Network error", 0, "NETWORK_ERROR"); } }; ``` **Retry logic**: ```tsx const fetchWithRetry = async ( url: string, options?: RequestInit, retries = 3 ) => { for (let i = 0; i < retries; i++) { try { return await fetchWithErrorHandling(url, options); } catch (error) { if (i === retries - 1) throw error; // Exponential backoff await new Promise((r) => setTimeout(r, Math.pow(2, i) * 1000)); } } }; ``` --- ### 4. Authentication **Token management**: ```tsx import * as SecureStore from "expo-secure-store"; const TOKEN_KEY = "auth_token"; export const auth = { getToken: () => SecureStore.getItemAsync(TOKEN_KEY), setToken: (token: string) => SecureStore.setItemAsync(TOKEN_KEY, token), removeToken: () => SecureStore.deleteItemAsync(TOKEN_KEY), }; // Authenticated fetch wrapper const authFetch = async (url: string, options: RequestInit = {}) => { const token = await auth.getToken(); return fetch(url, { ...options, headers: { ...options.headers, Authorization: token ? `Bearer ${token}` : "", }, }); }; ``` **Token refresh**: ```tsx let isRefreshing = false; let refreshPromise: Promise<string> | null = null; const getValidToken = async (): Promise<string> => { const token = await auth.getToken(); if (!token || isTokenExpired(token)) { if (!isRefreshing) { isRefreshing = true; refreshPromise = refreshToken().finally(() => { isRefreshing = false; refreshPromise = null; }); } return refreshPromise!; } return token; }; ``` --- ### 5. Offline Support Network-status detection with NetInfo and offline-first React Query setup: see [./references/offline-and-cancellation.md](./references/offline-and-cancellation.md). --- ### 6. Environment Variables **Using environment variables for API configuration**: Expo supports environment variables with the `EXPO_PUBLIC_` prefix. These are inlined at build time and available in your JavaScript code. ```tsx // .env EXPO_PUBLIC_API_URL=https://api.example.com EXPO_PUBLIC_API_VERSION=v1 // Usage in code const API_URL = process.env.EXPO_PUBLIC_API_URL; const fetchUsers = async () => { const response = await fetch(`${API_URL}/users`); return response.json(); }; ``` **Environment-specific configuration**: ```tsx // .env.development EXPO_PUBLIC_API_URL=http://localhost:3000 // .env.production EXPO_PUBLIC_API_URL=https://api.production.com ``` **Creating an API client with environment config**: ```tsx // api/client.ts const BASE_URL = process.env.EXPO_PUBLIC_API_URL; if (!BASE_URL) { throw new Error("EXPO_PUBLIC_API_URL is not defined"); } export const apiClient = { get: async <T,>(path: string): Promise<T> => { const response = await fetch(`${BASE_URL}${path}`); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); }, post: async <T,>(path: string, body: unknown): Promise<T> => { const response = await fetch(`${BASE_URL}${path}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); }, }; ``` **Important notes**: - Only variables prefixed with `EXPO_PUBLIC_` are exposed to the client bundle - Never put secrets (API keys with write access, database passwords) in `EXPO_PUBLIC_` variables—they're visible in the built app - Environment variables are inlined at **build time**, not runtime - Restart the dev server after changing `.env` files - For server-side secrets in API routes, use variables without the `EXPO_PUBLIC_` prefix **TypeScript support**: ```tsx // types/env.d.ts declare global { namespace NodeJS { interface ProcessEnv { EXPO_PUBLIC_API_URL: string; EXPO_PUBLIC_API_VERSION?: string; } } } export {}; ``` --- ### 7. Request Cancellation AbortController on unmount (React Query cancels automatically): see [./references/offline-and-cancellation.md](./references/offline-and-cancellation.md). --- ## Decision Tree ``` User asks about networking |-- Route-level data loading (web, SDK 55+)? | \-- Expo Router loaders — see references/expo-router-loaders.md | |-- Basic fetch? | \-- Use fetch API with error handling | |-- Need caching/state management? | |-- Complex app -> React Query (TanStack Query) | \-- Simpler needs -> SWR or custom hooks | |-- Authentication? | |-- Token storage -> expo-secure-store | \-- Token refresh -> Implement refresh flow | |-- Error handling? | |-- Network errors -> Check connectivity first | |-- HTTP errors -> Parse response, throw typed errors | \-- Retries -> Exponential backoff | |-- Offline support? | |-- Check status -> NetInfo | \-- Queue requests -> React Query persistence | |-- Environment/API config? | |-- Client-side URLs -> EXPO_PUBLIC_ prefix in .env | |-- Server secrets -> Non-prefixed env vars (API routes only) | \-- Multiple environments -> .env.development, .env.production | \-- Performance? |-- Caching -> React Query with staleTime |-- Deduplication -> React Query handles this \-- Cancellation -> AbortController or React Query ``` ## Common Mistakes **Wrong: No error handling** ```tsx const data = await fetch(url).then((r) => r.json()); ``` **Right: Check response status** ```tsx const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); ``` **Wrong: Storing tokens in AsyncStorage** ```tsx await AsyncStorage.setItem("token", token); // Not secure! ``` **Right: Use SecureStore for sensitive data** ```tsx await SecureStore.setItemAsync("token", token); ``` ## Example Invocations User: "How do I make API calls in React Native?" -> Use fetch, wrap with error handling User: "Should I use React Query or SWR?" -> React Query for complex apps, SWR for simpler needs User: "My app needs to work offline" -> Use NetInfo for status, React Query persistence for caching User: "How do I handle authentication tokens?" -> Store in expo-secure-store, implement refresh flow User: "API calls are slow" -> Check caching strategy, use React Query staleTime User: "How do I configure different API URLs for dev and prod?" -> Use `EXPO_PUBLIC_` env vars with .env.development and .env.production files User: "Where should I put my API key?" -> Client-safe keys: `EXPO_PUBLIC_` in .env. Secret keys: non-prefixed env vars in API routes only User: "How do I load data for a page in Expo Router?"
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る