Subidas e integración frontend

# Subidas de archivos con React y Uppy: reanudación, vistas previas, validación y procesamiento

Crea un componente de subida en React con Uppy: vistas previas, validación, progreso accesible, cancelación, reanudación y procesamiento con Transloadit.

Publicado el 24 de agosto de 2026

## Conclusiones clave

* Crea una instancia de Uppy por cada componente de subida montado y destrúyela cuando se desmonte el componente al que pertenece.
* Usa el estado y los eventos de Uppy como estado externo, en lugar de copiar el progreso, los archivos y los errores a un estado de React que compita con ellos.
* Trata las restricciones del cliente como retroalimentación inmediata y vuelve a aplicar la misma política en un Template o receptor de confianza.

Una subida de archivos con React es un pequeño sistema con estado, no solo un campo de entrada y una solicitud POST. El componente de subida debe resistir las nuevas renderizaciones, liberar recursos al desmontarse, explicar las restricciones antes de la transferencia, recuperarse de fallos de red habituales y distinguir los bytes subidos del procesamiento multimedia finalizado. Uppy proporciona esa máquina de estados de subida, mientras que React muestra el estado actual.

## En esta guía

1. [Define qué significa «completo» antes de escribir el componente](#react-file-uploads-with-uppy-section-1)
2. [Crea una instancia configurada de Uppy por cada componente de subida montado](#react-file-uploads-with-uppy-section-2)
3. [Muestra desde Uppy el progreso, la cancelación y el estado de la Assembly](#react-file-uploads-with-uppy-section-3)
4. [Usa las vistas previas y las restricciones como funciones de la interfaz, no como límites de confianza](#react-file-uploads-with-uppy-section-4)
5. [Diseña la reanudación según la interrupción que necesites superar](#react-file-uploads-with-uppy-section-5)
6. [Entrega los archivos transferidos a un flujo de trabajo multimedia asíncrono](#react-file-uploads-with-uppy-section-6)
7. [Prueba el ciclo de vida y el comportamiento ante fallos, no solo el caso ideal](#react-file-uploads-with-uppy-section-7)

## Lo más importante

* Obtén opciones firmadas y de corta duración para la Assembly desde un endpoint de servidor autenticado; nunca expongas un Auth Secret en el código de React.
* Usa una cantidad limitada de reintentos para los fallos transitorios, ofrece una opción explícita de cancelación y añade recuperación persistente solo cuando recuperarse tras una recarga sea un requisito real.
* Guarda el ID de la Assembly y concilia el procesamiento de forma independiente cuando el componente de subida pueda desaparecer antes de que finalice el flujo de trabajo.

## Define qué significa «completo» antes de escribir el componente

Un navegador puede terminar de enviar los bytes mientras los archivos multimedia resultantes aún se inspeccionan, transforman y exportan. Decide qué estado considera completado la interfaz: la selección del archivo, la transferencia, la creación de la Assembly, el procesamiento, el almacenamiento persistente o la publicación en la aplicación. Los tres niveles siguientes agrupan la selección del archivo y la transferencia bajo el éxito de la transferencia; la creación de la Assembly y el procesamiento, bajo el éxito del procesamiento; y el almacenamiento persistente y la publicación, bajo el éxito de la aplicación. Un componente de React puede mostrar varios de estos estados, pero no debe reducirlos a un único indicador de éxito.

En un flujo de trabajo de Transloadit, Uppy controla la cola y el estado de la transferencia en el navegador. El plugin de Transloadit crea una Assembly y asocia cada archivo local con ese flujo de trabajo. Tu aplicación debe conservar el ID de la Assembly en cuanto exista y, si el procesamiento puede durar más que la página, conciliar el resultado terminal fuera del componente. Una barra de progreso completa no es un registro persistente del recurso.

### Éxito de la transferencia

El receptor aceptó los bytes del archivo. Este es el estado que representa el progreso de la subida cuando el plugin no espera a que termine la codificación.

### Éxito del procesamiento

La Assembly alcanzó un estado final exitoso y produjo los Steps de resultados esperados.

### Éxito de la aplicación

La aplicación almacenó los identificadores de la Assembly y de los recursos, confirmó la propiedad y puso el resultado a disposición según las reglas del producto.

## Crea una instancia configurada de Uppy por cada componente de subida montado

Instala Core, Dashboard, el paquete de la interfaz de React, el plugin de Transloadit con mantenimiento activo y el validador de esquemas Zod para la respuesta de autorización. Importa una vez cada hoja de estilos de Uppy desde un punto de entrada estable para que su orden de carga sea predecible. El siguiente ejemplo de componente importa directamente los estilos del paquete; mueve esas importaciones al punto de entrada de la aplicación si allí es donde tu framework o empaquetador gestiona los estilos globales.

Construye Uppy una vez para toda la vida útil del formulario montado. Un inicializador diferido de `useState` en la siguiente sección proporciona a cada componente de subida montado su propia instancia sin reconstruirla durante cada nuevo renderizado. No crees un singleton compartido en el nivel del módulo, a menos que todas las superficies formen intencionalmente una única cola; de lo contrario, los formularios independientes verían y eliminarían los archivos de los demás.

La función asíncrona `assemblyOptions` solicita autorización a un endpoint de confianza inmediatamente antes de la subida. El endpoint debe autenticar y autorizar al usuario actual, aplicar controles contra abusos, elegir un Template restringido y devolver un payload firmado de corta duración. El navegador valida la estructura de la respuesta, pero nunca recibe el Auth Secret.

Instalar la interfaz de React y la integración con Transloadit

```
yarn add @uppy/core @uppy/dashboard @uppy/react @uppy/transloadit zod
```

Crear una instancia restringida de Uppy fuera de la ruta de renderizado

```
import Uppy from '@uppy/core'
import Transloadit from '@uppy/transloadit'
import { z } from 'zod'

const assemblyOptionsSchema = z.object({
  params: z.string().min(1),
  signature: z.string().regex(/^(sha1|sha256|sha384):[0-9a-f]+$/),
})

async function fetchAssemblyOptions(): Promise<z.infer<typeof assemblyOptionsSchema>> {
  const response = await fetch('/api/transloadit-params', {
    method: 'POST',
    headers: { Accept: 'application/json' },
  })

  if (!response.ok) {
    throw new Error('Could not authorize this upload')
  }

  const responseBody: unknown = await response.json().catch(() => null)
  const parsedOptions = assemblyOptionsSchema.safeParse(responseBody)
  if (!parsedOptions.success) {
    throw new Error('Could not authorize this upload')
  }

  return parsedOptions.data
}

export function createImageUploader(): Uppy {
  return new Uppy({
    autoProceed: false,
    restrictions: {
      allowedFileTypes: ['image/jpeg', 'image/png', 'image/webp'],
      maxFileSize: 50 * 1024 * 1024,
      maxNumberOfFiles: 5,
    },
  }).use(Transloadit, {
    assemblyOptions: fetchAssemblyOptions,
    retryDelays: [0, 1_000, 3_000, 5_000],
    waitForEncoding: false,
  })
}
```

## Muestra desde Uppy el progreso, la cancelación y el estado de la Assembly

Uppy es un almacén de estado externo. `useUppyState` suscribe React a valores seleccionados sin mantener una segunda cola en el estado del componente, mientras que `useUppyEvent` expone eventos que no son campos persistentes del almacén. El componente obtiene el número de archivos, el progreso agregado, el estado de la subida activa, el estado de error sin procesar y el evento de creación de la Assembly. Asigna el error a un mensaje estable para el usuario en lugar de mostrar el valor sin procesar, y no refleja los archivos individuales en un valor `useState` separado.

Dashboard permite seleccionar archivos, arrastrarlos y soltarlos, obtener vistas previas de los archivos locales compatibles, consultar el estado de cada archivo y usar los controles de subida. La región en vivo independiente proporciona a la aplicación circundante un anuncio conciso del estado, y el botón nativo deshabilitado indica si la cancelación está disponible. Mantén localizadas las etiquetas de Dashboard cuando el producto admita varios idiomas; aplica el mismo tratamiento al encabezado, el estado y los errores circundantes.

Destruye la instancia de Uppy cuando se desmonte el componente al que pertenece. Al destruirla, se cancela el trabajo en curso, se eliminan los plugins instalados y se liberan los listeners. Por lo tanto, un cambio de ruta no debería ser el único lugar donde se conserve el progreso importante: guarda el ID de la Assembly y cualquier registro de tareas de la aplicación antes de depender de trabajo que pueda continuar en otro lugar.

Renderizar el estado de Uppy en React y limpiar la instancia

```
import type { ReactNode } from 'react'

import Dashboard from '@uppy/react/dashboard'
import { useUppyEvent, useUppyState } from '@uppy/react'
import { useEffect, useState } from 'react'

import { createImageUploader } from './createImageUploader.ts'

import '@uppy/core/css/style.min.css'
import '@uppy/dashboard/css/style.min.css'

export function ReactFileUploader(): ReactNode {
  const [uppy] = useState(createImageUploader)
  const error = useUppyState(uppy, (state) => state.error)
  const fileCount = useUppyState(uppy, (state) => Object.keys(state.files).length)
  const isUploading = useUppyState(
    uppy,
    (state) => Object.keys(state.currentUploads).length > 0,
  )
  const progress = useUppyState(uppy, (state) => state.totalProgress)
  const [assemblyCreatedArgs, clearAssemblyCreated] = useUppyEvent(
    uppy,
    'transloadit:assembly-created',
  )
  useUppyEvent(uppy, 'cancel-all', clearAssemblyCreated)
  const [assembly] = assemblyCreatedArgs
  const assemblyId = assembly?.assembly_id

  useEffect(() => {
    return () => uppy.destroy()
  }, [uppy])

  let status = 'Choose up to five JPEG, PNG, or WebP images.'
  if (fileCount > 0) status = 'Ready to upload.'
  if (isUploading) status = `Upload ${progress}% complete.`
  if (!isUploading && progress === 100) status = 'Files transferred. Processing may continue.'
  if (error != null) status = 'Upload failed. Check the selected files and try again.'

  return (
    <section aria-labelledby="file-upload-heading">
      <h2 id="file-upload-heading">Upload images</h2>
      <Dashboard height={420} uppy={uppy} />
      <p aria-live="polite" role="status">
        {status}
      </p>
      {assemblyId != null ? (
        <p>
          Processing reference: <code>{assemblyId}</code>
        </p>
      ) : null}
      <button disabled={fileCount === 0} onClick={() => uppy.cancelAll()} type="button">
        Cancel and remove files
      </button>
    </section>
  )
}
```

## Usa las vistas previas y las restricciones como funciones de la interfaz, no como límites de confianza

Una vista previa local ayuda a detectar una selección incorrecta antes de incurrir en el costo de la subida. No es el resultado procesado ni demuestra que el archivo sea seguro, decodificable, esté orientado correctamente o tenga una etiqueta veraz. Limita el trabajo de la vista previa, ya que decodificar muchas imágenes grandes consume memoria del navegador. Para los formatos que el navegador no pueda previsualizar, muestra el nombre del archivo, el tipo declarado y el tamaño sin inventar una miniatura.

Las restricciones de Uppy rechazan pronto los errores evidentes: tipos permitidos, tamaño individual, tamaño total y cantidad de archivos. Repite los mismos límites en un receptor de confianza o en el Template guardado, porque quien realiza la llamada puede eludir React y modificar los metadatos del archivo. Usa el contenido detectado y un intento de procesamiento cuando corresponda; después, almacena únicamente los resultados aceptados. `allow_steps_override` debe permanecer desactivado cuando el navegador no deba sustituir el flujo de trabajo aprobado. Cuando una vista previa o una restricción rechace una selección, muestra un mensaje estable para el usuario y mantén fuera de la página las respuestas sin procesar del proveedor, las trazas de pila, las credenciales y los diagnósticos del almacenamiento.

### Respuesta rápida

Explica los formatos, la cantidad y el tamaño aceptados antes de la selección; luego, permite que Uppy rechace las infracciones conocidas junto al control.

### Política autoritativa

Aplica la autorización, los límites de bytes, las reglas sobre el contenido detectado, los límites de procesamiento y los destinos de exportación una vez que ya no se pueda confiar en el código del navegador.

### Fallos gestionados de forma segura

Detecta los fallos de autorización y subida en el límite de confianza, asígnales un único mensaje estable para el usuario y envía los diagnósticos sin procesar únicamente a los registros del servidor.

## Diseña la reanudación según la interrupción que necesites superar

El plugin de Transloadit sube archivos locales mediante el protocolo tus, que puede continuar una transferencia fallida desde un desplazamiento confirmado por el servidor mientras el recurso de subida siga siendo válido. `retryDelays` gestiona un conjunto limitado de fallos transitorios durante la vida útil de la instancia actual de Uppy. La cancelación es diferente: `cancelAll()` interrumpe intencionalmente el trabajo en curso, elimina los archivos y restablece el estado de subida, por lo que la interfaz debe indicar que se eliminará la selección.

Recargar la página destruye el estado en memoria de React y Uppy. La recuperación tras una recarga requiere un estado persistente en el cliente y recursos de subida compatibles en el servidor, como un flujo de trabajo con el plugin Golden Retriever configurado deliberadamente. Prueba ese comportamiento con la integración real de Transloadit antes de prometerlo. Los metadatos locales persistentes pueden quedar obsoletos, ser sensibles o no coincidir con una autorización vencida, por lo que debes definir su retención y una forma de descartar las entradas irrecuperables.

La capacidad de reanudar también tiene un plazo operativo. Una Assembly no puede admitir subidas indefinidamente, y los parámetros firmados de corta duración pueden vencer antes de que comience un reintento demorado. Distingue entre el reintento automático, pausar y reanudar, restaurar tras una recarga e iniciar una nueva Assembly; resuelven fallos diferentes y pueden reutilizar identificadores distintos.

## Entrega los archivos transferidos a un flujo de trabajo multimedia asíncrono

Un Template guardado debe describir el grafo de procesamiento permitido: `/upload/handle` recibe los archivos del navegador, `/file/filter` puede rechazar las entradas observadas no compatibles, los Robots de transformación generan derivados acotados y los Robots de almacenamiento exportan los resultados aprobados cuando el flujo de trabajo incluye almacenamiento persistente. La solicitud firmada selecciona ese Template; React no construye Steps arbitrarios ni transporta credenciales de almacenamiento permanentes.

Elige `waitForEncoding` según el contrato de la interfaz. Establecerlo en false permite que el navegador finalice después de la transferencia y es apropiado cuando la aplicación registra el ID de la Assembly, muestra un estado de procesamiento independiente y obtiene el resultado final mediante una Assembly Notification verificada o una consulta posterior de Assembly Status. Esperar la codificación puede mantener la interfaz alineada con un procesamiento breve, pero no sustituye una conciliación persistente si se cierra la pestaña.

Almacena el contexto de la aplicación junto al ID de la Assembly: usuario autenticado o inquilino, espacio previsto para el recurso, ID del Template, hora de creación y operación de la aplicación que la originó. Cuando llegue una notificación, verifica su firma, gestiona las entregas duplicadas de forma idempotente, confirma que la Assembly pertenezca al registro esperado y guarda solo los campos de resultados que necesite el producto.

## Prueba el ciclo de vida y el comportamiento ante fallos, no solo el caso ideal

Prueba el componente con un archivo pequeño permitido, un archivo demasiado grande, una extensión engañosa, un tipo no compatible, varios archivos en el límite de cantidad, una entrada de cero bytes, una conexión lenta, un intervalo sin conexión, un rechazo del servidor, el vencimiento de la autorización, una cancelación del usuario, el desmontaje del componente y una recarga de la página. Confirma qué estado se conserva, qué trabajo se cancela y qué mensaje recibe un usuario de teclado o lector de pantalla.

Prueba la ruta real de firma y procesamiento, además del comportamiento aislado de React. Una simulación puede demostrar que el botón se deshabilita o que cambia un estado, pero solo un caso de prueba integrado demuestra que los parámetros firmados coinciden, que el protocolo tus reanuda la transferencia desde el desplazamiento esperado, que el Template rechaza el contenido incorrecto, que se registra el ID de la Assembly y que la finalización se concilia una sola vez. Mantén pequeños los archivos de prueba y elimina los datos temporales de producción después de la ejecución.

### Ciclo de vida de React

Vuelve a renderizar sin reemplazar la instancia de Uppy; luego, desmonta el componente y verifica que se limpien los plugins y el trabajo activo del navegador.

### Interacción accesible

Selecciona archivos sin arrastrarlos y soltarlos, usa todos los controles con el teclado y verifica que el rechazo, el progreso, la cancelación y la finalización se anuncien mediante texto.

### Conciliación del procesamiento

Cierra la página después de crear la Assembly, entrega una notificación de finalización repetida y demuestra que exactamente un recurso de la aplicación alcanza el estado terminal correcto.

## Detalles técnicos que conviene conocer

* Uppy es un almacén externo con estado. Crearlo en el cuerpo de renderizado genera una instancia nueva que se descarta en cada renderizado y pierde los archivos en cola y el estado de subida. En cambio, conservar una sola instancia pero volver a ejecutar su configuración puede registrar plugins y listeners duplicados.
* El hook `useUppyState` se suscribe al almacén de Uppy mediante el contrato de almacén externo de React y selecciona únicamente el estado que necesita un componente.
* El Dashboard de React instala su plugin de interfaz cuando se monta y lo elimina cuando se desmonta; la aplicación sigue siendo responsable de destruir la instancia de Uppy que creó.
* Las restricciones de Uppy rechazan en el navegador las selecciones no permitidas, pero quienes invocan el sistema pueden eludir el código del navegador y los tipos MIME declarados pueden ser incorrectos, por lo que sigue siendo necesaria una validación confiable.
* El plugin de Transloadit crea una Assembly y sube los archivos locales a su endpoint del protocolo tus. Su callback asíncrono `assemblyOptions` puede obtener parámetros firmados inmediatamente antes de que comience una subida.
* La opción `retryDelays` reintenta las subidas mediante el protocolo tus tras fallos transitorios mientras la instancia de Uppy y el estado de subida sigan disponibles; por sí sola, no restaura una transferencia después de recargar o cerrar la pestaña.
* Llamar a `cancelAll()` emite la cancelación, interrumpe el trabajo activo mediante los plugins de subida instalados, elimina los archivos actuales y restablece el estado de subida de Uppy.
* Con `waitForEncoding` establecido en false, la subida de Uppy puede completarse después de transferir los archivos mientras la Assembly continúa procesándose. Conserva el ID de la Assembly y usa notificaciones verificadas o una consulta de Assembly Status para lograr una finalización persistente.

## Un enfoque práctico

1. 1\
   Define los archivos aceptados, el destino de los bytes, el Template de procesamiento y el estado final de la aplicación antes de crear el componente.
2. 2\
   Crea una instancia configurada de Uppy, representa Dashboard y un estado accesible desde su almacén, y libera sus recursos al desmontarla.
3. 3\
   Emite en el servidor opciones firmadas y restringidas para la Assembly, y vuelve a aplicar en el Template los límites de archivos y las comprobaciones del contenido observado.
4. 4\
   Prueba el rechazo, la interrupción, la cancelación, el reintento, el desmontaje, la recarga, la autorización vencida y la finalización asíncrona.

Un flujo de trabajo multimedia de cuatro etapas

## Cuándo resulta útil Transloadit

Usa el React Dashboard con mantenimiento activo de Uppy y el plugin de Transloadit cuando una aplicación de React necesite una interfaz de subida pulida, transferencia reanudable mediante el protocolo tus y Steps de validación y transformación administrados del lado del servidor en un Template guardado. Obtén opciones firmadas y de corta duración para la Assembly desde un servidor de confianza, y conserva el ID de cada Assembly cuando el procesamiento pueda continuar después de que se cierre la página.

## Límite de la arquitectura

React controla el ciclo de vida del componente y muestra el estado de la subida. Uppy controla la selección de archivos en el navegador, las vistas previas, las restricciones, el estado de la transferencia y los controles para reintentar o cancelar. Transloadit autoriza y ejecuta el flujo de trabajo multimedia guardado. La aplicación sigue siendo responsable de los permisos del usuario, los registros persistentes de los recursos, la política de publicación y la conciliación después de desmontar el componente.

## Preguntas frecuentes

### ¿Se debe crear Uppy dentro de un componente de React?

Sí, cuando ese componente controle la cola, pero créalo con un inicializador de estado diferido para que los rerenders reutilicen una sola instancia. Destruye la instancia al desmontarlo. Usa un proveedor compartido solo cuando varios componentes operen intencionalmente sobre el mismo componente de subida.

### ¿El plugin de Transloadit necesita un plugin Tus de Uppy por separado?

No, para los archivos locales enviados a Transloadit. El plugin de Transloadit configura las subidas mediante el protocolo tus al endpoint de la Assembly. Usa el plugin Tus independiente cuando el destino sea un servidor tus separado y no una Assembly de Transloadit.

### ¿Son seguras las restricciones de archivos de Uppy?

No. Mejoran la información que ofrece el navegador, pero las solicitudes pueden eludir React y los metadatos de los archivos pueden ser falsos. Repite la autorización, los límites de bytes, la validación del contenido observado, las restricciones del flujo de trabajo y la política de almacenamiento en límites de confianza.

### ¿La vista previa de una imagen en Uppy cambia las dimensiones del archivo subido?

No. Una vista previa forma parte del estado de la interfaz del navegador. Conserva la fuente seleccionada y crea derivados reproducibles en el flujo de trabajo de procesamiento, a menos que el producto implemente deliberadamente una etapa independiente de preprocesamiento del lado del cliente.

### ¿retryDelays reanudará una subida después de recargar la página?

No. Los intervalos entre reintentos permiten afrontar fallos transitorios mientras el estado actual del componente de subida siga disponible. La recuperación tras una recarga requiere metadatos persistentes en el cliente y un recurso de subida válido en el servidor, y debe probarse como una función independiente.

### ¿Cuándo se debe activar waitForEncoding?

Actívalo cuando la interfaz montada deba esperar a que termine un procesamiento breve y mostrar directamente sus resultados. Déjalo desactivado cuando la transferencia deba finalizar pronto; después, conserva el ID de la Assembly y concilia el procesamiento mediante notificaciones verificadas o consultas de estado.

## Crea el flujo de trabajo

Pasa del concepto a una Assembly probada con documentación de Robots y demos funcionales.

* [Firma solicitudes de Assembly creadas en el navegador](/es/docs/api/authentication.md)
* [Comprende las subidas reanudables](/es/docs/api/resumable-uploads.md)
* [Lee la documentación de Uppy para React⁠](https://uppy.io/docs/react/)
* [Configura el plugin de Transloadit para Uppy⁠](https://uppy.io/docs/transloadit/)
* [Evalúa la recuperación tras una recarga con Golden Retriever⁠](https://uppy.io/docs/golden-retriever/)
* [Concilia el procesamiento con las Assembly Notifications](/es/docs/topics/webhooks.md)
* [Interpreta la respuesta de Assembly Status](/es/docs/api/assembly-status-response.md)
* [Lee la documentación de la API](/es/docs.md)
* [Explora demos funcionales EN (English)](/demos.md)
* [Crea un Workspace gratuito](/c/signup/)

Subidas e integración frontend

## Continúa con guías relacionadas

* [Guía de API de subida de archivos: arquitectura, seguridad y selección de proveedores](/es/guides/file-upload-api-guide.md)\
  Elige e implementa una API de subida comparando arquitectura, reanudación, transferencia directa a la nube, seguridad, límites de almacenamiento y proveedores.
* [Subidas seguras de archivos en Next.js con Uppy y Templates firmados de Transloadit](/es/guides/secure-file-uploads-nextjs-uppy.md)\
  Crea una subida segura en Next.js App Router con Uppy: firma en servidor, Template bloqueado, validación autoritativa, transferencia reanudable y fin asíncrono.
* [Cómo aceptar subidas grandes pese a una conexión interrumpida](/es/guides/resumable-uploads-for-large-files.md)\
  Acepta subidas de varios gigabytes mediante el protocolo tus, reanúdalas tras perder la conexión y mantén viva la Assembly hasta terminarlas.
* [Mejores bibliotecas JavaScript para subir archivos: Uppy vs FilePond vs Dropzone](/es/guides/best-javascript-file-upload-libraries.md)\
  Compara Uppy, FilePond y Dropzone según el protocolo de transferencia, el modelo de interfaz, la recuperación, la integración y el mantenimiento a largo plazo.
