expo-data-fetching
Acerca de
Esta habilidad proporciona una guía completa para implementar y depurar todas las operaciones relacionadas con redes en proyectos de Expo. Cubre APIs principales, bibliotecas populares como React Query/SWR y temas avanzados que incluyen manejo de errores, almacenamiento en caché y soporte sin conexión. Los desarrolladores deben utilizarla para cualquier solicitud de API, configuración de obtención de datos o resolución de problemas de red.
Instalación rápida
Claude Code
Recomendadonpx skills add expo/skills -a claude-code/plugin add https://github.com/expo/skillsgit clone https://github.com/expo/skills.git ~/.claude/skills/expo-data-fetchingCopia y pega este comando en Claude Code para instalar esta habilidad
Documentación
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:
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:
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:
// 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:
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:
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:
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:
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:
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:
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.
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.
// .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:
// .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:
// 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
.envfiles - For server-side secrets in API routes, use variables without the
EXPO_PUBLIC_prefix
TypeScript support:
// 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.
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
const data = await fetch(url).then((r) => r.json());
Right: Check response status
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
Wrong: Storing tokens in AsyncStorage
await AsyncStorage.setItem("token", token); // Not secure!
Right: Use SecureStore for sensitive data
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?" -> See references/expo-router-loaders.md for route-level loaders (web, SDK 55+). For native, use React Query or fetch.
Repositorio GitHub
Frequently asked questions
What is the expo-data-fetching skill?
expo-data-fetching is a Claude Skill by expo. Skills package instructions and resources that Claude loads on demand, so Claude can perform expo-data-fetching-related tasks without extra prompting.
How do I install expo-data-fetching?
Use the install commands on this page: add expo-data-fetching to Claude Code as a plugin, or clone its repository into your skills directory, then restart Claude so it picks up the skill.
What category does expo-data-fetching belong to?
expo-data-fetching is in the Testing category, tagged react, api and data.
Is expo-data-fetching free to use?
Yes. expo-data-fetching is listed on AIMCP and free to install. It runs inside Claude, so no separate service account is required to use the skill itself.
Habilidades relacionadas
Esta Skill de Claude ejecuta el benchmark lm-evaluation-harness para evaluar modelos de lenguaje en más de 60 tareas académicas estandarizadas como MMLU y GSM8K. Está diseñada para que los desarrolladores comparen la calidad de los modelos, realicen seguimiento del progreso del entrenamiento o reporten resultados académicos. La herramienta admite varios backends, incluidos modelos de HuggingFace y vLLM.
Esta habilidad proporciona conocimiento integral para implementar Cron Triggers de Cloudflare y programar Workers mediante expresiones cron. Cubre la configuración de tareas periódicas, trabajos de mantenimiento y flujos de trabajo automatizados, manejando problemas comunes como expresiones cron inválidas y inconvenientes de zonas horarias. Los desarrolladores pueden utilizarla para configurar manejadores programados, probar activadores cron e integrar con Workflows y Green Compute.
Esta habilidad de Claude proporciona un kit de herramientas basado en Playwright para probar aplicaciones web locales mediante scripts de Python. Permite verificación de frontend, depuración de interfaz de usuario, captura de pantallas y visualización de registros, mientras gestiona los ciclos de vida del servidor. Úsela para tareas de automatización de navegadores, pero ejecute los scripts directamente en lugar de leer su código fuente para evitar contaminación del contexto.
Esta habilidad ayuda a los desarrolladores a completar el trabajo terminado verificando que las pruebas pasen y luego presentando opciones estructuradas de integración. Guía el flujo de trabajo para fusionar, crear PRs o limpiar ramas después de que se completa la implementación. Úsala cuando tu código esté listo y probado para finalizar sistemáticamente el proceso de desarrollo.
