Communitygithub.com

patrones-react-native

Patrones para aplicaciones React Native y Expo: navegación con Expo Router, separación de estado (servidor/cliente/ruta/formulario), obtención de datos con TanStack Query y Zod, listas eficientes, estilos con NativeWind/StyleSheet, APIs nativas y almacenamiento seguro. Útil al construir o editar pantallas, componentes, navegación o capas de datos en React Native / Expo.

¿Qué es patrones-react-native?

Este skill proporciona un conjunto de patrones prácticos y contrastados para construir aplicaciones React Native de producción con Expo, abordando desde la estructura del proyecto basada en Expo Router hasta la gestión de estado, la obtención de datos validados con Zod y TanStack Query, el renderizado eficiente de listas, las opciones de estilo (NativeWind o StyleSheet), el acceso a APIs nativas mediante hooks, y el almacenamiento seguro de tokens. Está diseñado para desarrolladores que utilizan el flujo de trabajo gestionado de Expo con la Nueva Arquitectura y evita patrones web que no aplican en React Native (sin DOM, sin barra de URL). El skill se activa al construir o editar pantallas, componentes, navegación o capas de datos, y proporciona ejemplos completos de código, incluidos formularios con React Hook Form y Zod, y una pantalla completa que integra ruta, consulta, lista y estados de carga, error y vacío. También documenta anti-patrones comunes y mejores prácticas, como la validación de parámetros de enlace profundo, la virtualización de listas, el uso de `expo-secure-store` para tokens y la memoización de componentes de lista.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/react-native-patterns

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Patrones de React Native / Expo

Patrones prácticos para construir aplicaciones React Native de producción con Expo. Cubre navegación, estado, obtención de datos, listas, estilos y APIs nativas. Se complementa con el conjunto de reglas rules/react-native/: las reglas dicen qué aplicar, este skill muestra cómo.

Las bibliotecas mencionadas (NativeWind, Zustand/Jotai, TanStack Query) son opciones comunes y bien establecidas que se muestran como ilustración — los patrones importan más que el paquete específico, y cualquier equivalente funciona. Zod se utiliza para la validación para mantener la coherencia con las reglas typescript/ existentes de ECC.

Estos patrones asumen el flujo de trabajo gestionado de Expo (Expo Router, EAS, módulos expo-*) en la Nueva Arquitectura (el valor predeterminado en SDKs recientes de Expo, obligatorio a partir de SDK 55+). NO asumen el DOM del navegador — React Native no tiene <div>, ni barra de URL, ni valores predeterminados de obtención de datos web.

Cuándo activarlo

Utiliza este skill cuando:

  • Construyas o edites pantallas, componentes o navegación de React Native / Expo
  • Configures el enrutamiento con Expo Router (directorio app/ basado en archivos)
  • Decidas dónde pertenece el estado (caché del servidor vs. almacén del cliente vs. parámetros de ruta vs. formulario)
  • Implementes la obtención de datos con TanStack Query y valides las respuestas con Zod
  • Renderices listas largas o pesadas
  • Elijas o apliques un enfoque de estilo (NativeWind o StyleSheet)
  • Accedas a APIs de dispositivos nativos (cámara, ubicación, notificaciones) o almacenamiento seguro
  • Revises código RN para problemas específicos de dispositivos móviles

NO utilices los patrones web/React-DOM aquí — URL-como-estado, <div> y SWR-para-navegador no aplican en React Native.

Conceptos básicos

Estructura del proyecto (Expo Router)

Enrutamiento basado en archivos bajo app/. Mantén los archivos de ruta ligeros: leen y validan parámetros, luego delegan en un componente de pantalla que reside en components/ o features/.

app/
  _layout.tsx          # pila raíz
  (tabs)/
    _layout.tsx        # navegador de pestañas
    index.tsx          # Inicio
  user/[id].tsx        # ruta dinámica
components/
features/
  user/UserProfile.tsx

Navegación: validar parámetros de ruta

Los enlaces profundos y las rutas dinámicas entregan cadenas no confiables. Valídalas con Zod antes de usarlas.

// app/user/[id].tsx
import { useLocalSearchParams, router } from 'expo-router'
import { z } from 'zod'
import { UserProfile } from '@/features/user/UserProfile'

const Params = z.object({ id: z.string().uuid() })

export default function UserRoute() {
  const parsed = Params.safeParse(useLocalSearchParams())
  if (!parsed.success) {
    router.replace('/not-found')
    return null
  }
  return <UserProfile userId={parsed.data.id} />
}

Estado: mantener las preocupaciones separadas

No dupliques datos del servidor en un almacén del cliente. Cada preocupación tiene su propio lugar.

PreocupaciónOpciones comunes
Estado del servidor (datos remotos)una biblioteca de caché del servidor (TanStack Query, SWR)
Estado del cliente/UIun almacén ligero (Zustand, Jotai) o Contexto
Estado de ruta/navegaciónparámetros de Expo Router
Estado del formulariouna biblioteca de formularios (ej. React Hook Form) + validación de esquema
Secretos / tokensexpo-secure-store
Persistencia no secretaAsyncStorage / MMKV

Prefiere useState local hasta que el estado realmente necesite ser compartido.

Obtención de datos: una biblioteca de caché + Zod

Utiliza una biblioteca de caché del servidor (TanStack Query, SWR) en lugar de fetch-en-useEffect. Valida en el límite e infiere tipos a partir del esquema. Maneja los estados de carga, error y vacío explícitamente. (El ejemplo usa TanStack Query).

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { z } from 'zod'

const User = z.object({ id: z.string(), email: z.string().email() })
type User = z.infer<typeof User>

export function useUser(id: string) {
  return useQuery({
    queryKey: ['user', id],
    queryFn: async (): Promise<User> => User.parse(await api.getUser(id)),
  })
}

export function useUpdateEmail(id: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (email: string) => api.updateEmail(id, email),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['user', id] }),
  })
}

Listas: virtualizar, nunca mapear un array grande en un ScrollView

import { FlatList } from 'react-native'

<FlatList
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={renderItem}          // memoizado
  initialNumToRender={10}
  windowSize={5}
/>

Usa FlashList (Shopify) para listas grandes o heterogéneas.

Estilo: elegir un sistema

StyleSheet.create() es la opción nativa del framework; las bibliotecas de clases de utilidad (ej. NativeWind) son una alternativa común. Elige uno y mantente consistente. Nunca construyas objetos de estilo en línea en JSX en rutas críticas.

// NativeWind
<View className="p-4 rounded-2xl bg-white">
  <Text className="text-base font-semibold">Hola</Text>
</View>

// StyleSheet
const styles = StyleSheet.create({ card: { padding: 16, borderRadius: 16, backgroundColor: '#fff' } })
<View style={styles.card}>...</View>

APIs nativas: envolver en hooks, limpiar efectos

Mantén las llamadas y suscripciones del SDK de Expo dentro de hooks use*, no en JSX. Siempre limpia.

import { useEffect, useState } from 'react'
import * as Location from 'expo-location'

type LocationState =
  | { status: 'loading' }
  | { status: 'denied' }
  | { status: 'granted'; coords: Location.LocationObjectCoords }

export function useCurrentLocation() {
  // Rastrea el estado, no solo las coordenadas — para que la UI pueda distinguir "todavía cargando"
  // de "permiso denegado" y mostrar un mensaje procesable.
  const [state, setState] = useState<LocationState>({ status: 'loading' })

  useEffect(() => {
    let active = true
    ;(async () => {
      const { status } = await Location.requestForegroundPermissionsAsync()
      if (status !== 'granted') {
        if (active) setState({ status: 'denied' })
        return
      }
      const pos = await Location.getCurrentPositionAsync({})
      if (active) setState({ status: 'granted', coords: pos.coords })
    })()
    return () => { active = false }   // ignora resultado obsoleto después de desmontar
  }, [])

  return state
}

Almacenamiento seguro para tokens

import * as SecureStore from 'expo-secure-store'

await SecureStore.setItemAsync('auth_token', token)   // Llavero / Almacén de claves
const token = await SecureStore.getItemAsync('auth_token')

Ejemplos de código

Una pantalla completa: ruta → consulta → lista → estados

// app/(tabs)/orders.tsx
import { memo, useCallback } from 'react'
import { FlatList, Text, View } from 'react-native'
import { useQuery } from '@tanstack/react-query'
import { z } from 'zod'

const OrderSchema = z.object({ id: z.string(), total: z.number(), status: z.string() })
const OrdersSchema = z.array(OrderSchema)
type Order = z.infer<typeof OrderSchema>

function useOrders() {
  return useQuery({
    queryKey: ['orders'],
    queryFn: async () => OrdersSchema.parse(await api.listOrders()),
  })
}

// Memoizado para que su referencia sea estable entre renderizados (ver la guía de listas).
const OrderRow = memo(function OrderRow({ item }: { item: Order }) {
  return (
    <View className="px-4 py-3 border-b border-neutral-200">
      <Text className="font-medium">#{item.id}</Text>
      <Text className="text-neutral-500">{item.status} · ${item.total}</Text>
    </View>
  )
})

export default function OrdersScreen() {
  const { data, isLoading, isError, refetch, isRefetching } = useOrders()
  const renderItem = useCallback(({ item }: { item: Order }) => <OrderRow item={item} />, [])

  if (isLoading) return <Centered><Text>Cargando…</Text></Centered>
  if (isError) return <Centered><Text accessibilityRole="alert">No se pudieron cargar los pedidos.</Text></Centered>
  if (!data?.length) return <Centered><Text>Aún no hay pedidos.</Text></Centered>

  return (
    <FlatList
      data={data}
      keyExtractor={(o) => o.id}
      onRefresh={refetch}
      refreshing={isRefetching}
      renderItem={renderItem}
    />
  )
}

Un formulario: React Hook Form + resolvedor Zod

import { useForm, Controller } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { TextInput, Button, Text } from 'react-native'

const Schema = z.object({ email: z.string().email('Correo electrónico inválido') })
type FormValues = z.infer<typeof Schema>

export function EmailForm({ onSubmit }: { onSubmit: (v: FormValues) => void }) {
  const { control, handleSubmit, formState: { errors } } = useForm<FormValues>({
    resolver: zodResolver(Schema),
    defaultValues: { email: '' },
  })

  return (
    <>
      <Controller
        control={control}
        name="email"
        render={({ field: { value, onChange, onBlur } }) => (
          <TextInput
            value={value}
            onChangeText={onChange}
            onBlur={onBlur}
            autoCapitalize="none"
            keyboardType="email-address"
            accessibilityLabel="Dirección de correo electrónico"
          />
        )}
      />
      {errors.email && <Text accessibilityRole="alert">{errors.email.message}</Text>}
      <Button title="Guardar" onPress={handleSubmit(onSubmit)} />
    </>
  )
}

Anti-patrones

// INCORRECTO: array grande mapeado dentro de un ScrollView (sin virtualización, entrecortado, mucha memoria)
<ScrollView>{items.map((i) => <Row key={i.id} item={i} />)}</ScrollView>
// CORRECTO: FlatList / FlashList

// INCORRECTO: datos del servidor copiados en un almacén del cliente (dos fuentes de verdad, datos obsoletos)
const useStore = create((set) => ({ users: [], setUsers: (u) => set({ users: u }) }))
useEffect(() => { getUsers().then(setUsers) }, [])
// CORRECTO: useQuery posee el estado del servidor; deriva lo que necesites

// INCORRECTO: tokens en AsyncStorage (no cifrados)
await AsyncStorage.setItem('auth_token', token)
// CORRECTO: expo-secure-store

// INCORRECTO: confiar en parámetros de enlace profundo
const { id } = useLocalSearchParams(); fetchUser(id)
// CORRECTO: validar con Zod antes de usar

// INCORRECTO: objeto de estilo en línea recreado en cada renderizado en una ruta crítica
<View style={{ padding: 16, backgroundColor: '#fff' }} />
// CORRECTO: StyleSheet.create en ámbito de módulo, o className de NativeWind

// INCORRECTO: secreto real enviado en el paquete
const STRIPE_SECRET = 'sk_live_...'
// CORRECTO: mantener llamadas privilegiadas en el servidor; enviar solo claves públicas protegidas por reglas del backend

Mejores prácticas

  • Mantén los archivos de ruta ligeros; coloca la lógica en componentes de pantalla y hooks use*.
  • Valida cada entrada externa (respuestas de API, parámetros de ruta, cargas push) con Zod.
  • Deja que TanStack Query posea el estado del servidor; mantén los almacenes del cliente pequeños.
  • Siempre renderiza estados de carga, error y vacío — nunca solo un spinner sin respaldo.
  • Virtualiza listas; memoiza renderItem; proporciona un keyExtractor estable.
  • Usa react-native-reanimated para animaciones (hilo de UI); evita trabajo pesado en el hilo de JS.
  • Almacena tokens en expo-secure-store; nunca confíes en el cliente para la autorización.
  • Respeta las áreas seguras, el Tipo Dinámico y los roles/etiquetas de accesibilidad desde el principio.
  • Confirma la compatibilidad con la Nueva Arquitectura para cada dependencia nativa antes del lanzamiento.

Skills relacionados

  • frontend-patterns — Patrones de React/Next.js (web); útil para conceptos compartidos de React, pero específicos del DOM.
  • coding-standards — Modismos de TypeScript/JavaScript que aplican al código RN.
  • tdd-workflow, e2e-testing — Proceso de pruebas (usa Jest + React Native Testing Library, Maestro/Detox para RN).
  • security-review — Lista de verificación de seguridad general que complementa la guía de paquete/secreto de RN anterior.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Skills relacionados