Mejores prácticas de bibliotecas React
Un resumen condensado de las 25 mejores prácticas más importantes extraídas de cada página en esta sección.
- Devuelve toDataStreamResponse: Un manejador de ruta de AI SDK debe devolver
result.toDataStreamResponse()(noresult.textoNextResponse.json); de lo contrario, envías un blob JSON de respuesta completa y la UI de transmisiónuseChatnunca se actualiza token-por-token. - Establece maxSteps para llamadas de herramientas: Las herramientas definidas sin
maxStepspredeterminan a un solo paso, por lo que el modelo puede llamar a una herramienta pero nunca ver su resultado y la conversación se detiene — aumenta a la máxima profundidad de razonamiento que realmente deseas. - Usa generateObject con Zod: Para salida estructurada,
generateObject({ schema })con un esquema Zod impone la forma en la capa SDK; solicitar JSON y análisis manual es frágil y desperdicia tokens en instrucciones de formato. - Codifica la carga útil de Lambda como Uint8Array:
InvokeCommandrechaza objetos simples en tiempo de ejecución — envuelve connew TextEncoder().encode(JSON.stringify(payload))y decodifica la respuesta simétricamente, respetando los límites de carga útil de 6 MB sincrónico / 256 KB asincrónico. - Verifica FunctionError, no Catch: Los errores en tiempo de ejecución de Lambda llegan como un campo
FunctionErroren la respuesta, no como una excepción lanzada, por lo que inspecciona el sobre de respuesta — las invocaciones asincrónicas (Event) descartan errores silenciosamente a menos que configures un DLQ. - Ten en cuenta los límites de caracteres de Polly: El motor neural se limita a 3.000 caracteres por solicitud y el motor estándar a 6.000, así que divide texto largo en límites de oración y verifica soporte neural con
DescribeVoicesCommandantes de cambiar voces. - Envuelve SSML en speak y escapa: La entrada SSML requiere
TextType: "ssml"y debe ser XML válido dentro de<speak>...</speak>con&,<,>escapados; también evita salidapcmpara navegadores ya que es audio crudo — usamp3uogg_vorbis. - Carga a S3 mediante PUT prefirmado: Genera una URL prefirmada en el servidor y permite que el navegador
PUTdirectamente a S3 para que las cargas grandes eviten el límite de cuerpo de solicitud de Next.js (1 MB predeterminado) y nunca toquen el ancho de banda del servidor. - Configura CORS de bucket para PUT: Las cargas de navegador a S3 requieren reglas CORS explícitas de bucket que enumeren tu origen, el método
PUTy el encabezadoContent-Type— y siempre estableceContentTypeen el comando prefirmado para que el objeto no se guarde comoapplication/octet-stream. - Mantén los SDKs de AWS solo en el servidor: Nunca importes
@aws-sdk/client-s3,client-lambdaoclient-pollydesde un archivo"use client"— las credenciales terminan en el bundle del navegador y AWS SDK v3 hincha el JS del cliente; usa Server Actions o Route Handlers. - Usa parseISO, no new Date:
new Date("2026-04-06")analiza cadenas ISO de solo fecha como medianoche UTC y se desplaza visiblemente en zonas no UTC, por lo que prefiereparseISO(másdate-fns-tzpara trabajo consciente de zona) para evitar errores silenciosos de un día fuera. - Ten en cuenta MM vs mm tokens de formato: date-fns sigue Unicode TR#35, donde
MMes mes,mmes minutos yDDes inválido (usadd) — los errores de caso se compilan correctamente y producen cadenas silenciosamente incorrectas. - Formatea fechas en el cliente: Las fechas formateadas renderizadas en el servidor causan desincronización de hidratación siempre que la zona horaria del servidor difiera de la del cliente, así que formatea en un Componente Cliente después del montaje o pasa la marca de tiempo sin procesar y formatea en el navegador.
- Envuelve elementos de arrastre en DragOverlay:
DragOverlayrenderiza la vista previa de arrastre fuera del flujo del DOM y soluciona el problema de "salto de elementos" cuando el espacio original se colapsa; combina con opacidad reducida en el original para una visual estable. - Requiere movimiento del puntero para comenzar el arrastre: Añade
activationConstraint: { distance: 8 }(o un retraso) aPointerSensorpara que un solo clic no inicie un arrastre; sin esto, cada clic en un elemento ordenable desencadena arrastres accidentales. - IDs dnd-kit únicos globalmente: dnd-kit identifica elementos solo por ID en todos los contenedores, por lo que IDs duplicados en columnas rompen descargas de múltiples contenedores — usa UUIDs o claves prefijadas por contenedor en lugar de índices por lista.
- Importa desde lodash-es: Usa importaciones nombradas desde
lodash-espara que el empaquetador tree-shake las utilidades sin usar;import _ from "lodash"trae toda la construcción CJS de ~70 KB incluso para un solo ayudante. - Memoiza la creación de debounce: Crear
debounce(fn, 300)en línea en render devuelve una instancia nueva cada renderizado y nunca acumula llamadas; envuelve la creación enuseMemo/useCallbacky llama a.cancel()en la limpiezauseEffectpara que las invocaciones pendientes no se disparen después del desmontaje. - Pasa un objetivo nuevo a merge: El
merge(target, source)de Lodash muta su primer argumento, así que siempre pasa un nuevo{}(ocloneDeepprimero) como objetivo; también prefierestructuredClonenativo sobrecloneDeepa menos que necesites soporte de función o instancia de clase. - Genera un AUTH_SECRET de 32+ caracteres: Auth.js falla en producción sin
AUTH_SECRETy los secretos débiles comprometen cada sesión — genera uno connpx auth secrety usa valores distintos por entorno para que una clave de desarrollo filtrada nunca comprometa prod. - El proveedor de credenciales es solo JWT: El proveedor de credenciales no puede usar sesiones de base de datos incluso con un adaptador instalado, y extender tipos de sesión requiere tanto el par de callback
jwt/sessioncomo una ampliación de módulo entypes/next-auth.d.tso TypeScript se desvía del tiempo de ejecución. - Usa un Prisma Client Singleton: En desarrollo, adjunta el cliente Prisma a
globalThispara que la recarga de módulo en caliente no abra un nuevo pool de conexiones en cada guardado — sin esto la base de datos rápidamente rechaza conexiones y el servidor de desarrollo parece colgarse. - Convierte BigInt antes de la serialización: Los campos BigInt de Prisma no pueden cruzar el límite Servidor→Cliente a través de JSON, así que mapéalos a
NumberoStringantes de pasar a Componentes Cliente, y selecciona solo las relaciones que necesitas (coninclude/select) para evitar consultas N+1. - QueryClient vive en useState: Construye el
QueryClientde TanStack Query dentro deuseState(() => new QueryClient())dentro de un proveedor cliente; un cliente a nivel de módulo en un Server Component filtra el estado de caché entre solicitudes de usuario y filtra datos entre usuarios. - Entiende staleTime vs gcTime:
staleTimecontrola cuándo se considera que los datos son frescos y si ocurren refetches;gcTimecontrola cuánto tiempo las consultas inactivas permanecen en la caché —staleTime: Infinityaún permite la recolección de basura, y las mutaciones nunca auto-invalidan consultas relacionadas sininvalidateQueriesexplícito.