Points clés à retenir
- Créez une seule instance Uppy par outil de téléversement monté et détruisez-la lorsque le composant qui la possède est démonté.
- Utilisez l’état et les événements d’Uppy comme état externe au lieu de copier la progression, les fichiers et les erreurs dans un état React concurrent.
- Considérez les restrictions côté client comme un retour immédiat et faites à nouveau appliquer la même politique dans un Template ou un service récepteur de confiance.
Le téléversement de fichiers dans React est un petit système avec état, pas simplement un champ de saisie et une requête POST. L’outil de téléversement doit résister aux nouveaux rendus, libérer ses ressources au démontage, expliquer les restrictions avant le transfert, se remettre des pannes réseau courantes et distinguer les octets téléversés du traitement des médias terminé. Uppy fournit cette machine à états de téléversement, tandis que React affiche l’état courant.
L’essentiel
- Récupérez des options d’Assembly signées à courte durée de validité auprès d’un point de terminaison serveur soumis à authentification ; n’exposez jamais d’Auth Secret dans le code React.
- Limitez les nouvelles tentatives en cas de défaillance passagère, rendez l’annulation explicite et n’ajoutez une récupération fondée sur des données persistées que si la récupération après rechargement est un besoin réel.
- Conservez l’identifiant de l’Assembly et synchronisez l’état du traitement indépendamment lorsque le composant de téléversement peut disparaître avant la fin du flux de travail.
Définir ce que signifie « terminé » avant d’écrire le composant
Un navigateur peut finir d’envoyer les octets alors que l’inspection, la transformation et l’exportation des médias qui en résultent sont encore en cours. Déterminez quel état l’interface considère comme terminé : sélection des fichiers, transfert, création de l’Assembly, traitement, stockage durable ou publication dans l’application. Les trois niveaux ci-dessous regroupent la sélection des fichiers et le transfert sous la réussite du transfert, la création de l’Assembly et le traitement sous la réussite du traitement, et le stockage durable et la publication sous la réussite applicative. Un composant React peut afficher plusieurs de ces états, mais il ne devrait pas les fusionner en un seul indicateur de réussite.
Dans un flux de travail Transloadit, Uppy gère la file d’attente côté navigateur et l’état du transfert. Le plugin Transloadit crée une Assembly et associe chaque fichier local à ce flux de travail. Votre application devrait conserver l’identifiant de l’Assembly dès qu’il existe, puis synchroniser le résultat terminal en dehors du composant lorsque le traitement peut se poursuivre après la fermeture de la page. Une barre de progression remplie ne constitue pas un enregistrement durable du fichier média.
Réussite du transfert
Le service récepteur a accepté les octets du fichier. C’est l’état que représente la progression du téléversement lorsque le plugin n’attend pas l’encodage.
Réussite du traitement
L’Assembly a atteint un état terminal de réussite et produit les Steps de résultat attendus.
Réussite applicative
L’application a enregistré les identifiants de l’Assembly et des fichiers médias, confirmé leur appartenance et rendu le résultat disponible selon ses règles produit.
Créer une seule instance Uppy configurée par outil de téléversement monté
Installez Core, Dashboard, le paquet d’interface React, le plugin Transloadit maintenu et le validateur de schéma Zod pour la réponse d’autorisation. Importez chaque feuille de style Uppy une fois depuis un point d’entrée stable afin que son ordre de chargement reste prévisible. L’exemple de composant ci-dessous importe directement les styles du paquet ; déplacez ces imports vers le point d’entrée de l’application si votre framework ou votre outil de regroupement y gère les styles globaux.
Créez Uppy dans l’effet du composant qui possède l’instance et détruisez cette même instance lors du nettoyage. Chaque outil de téléversement monté dispose ainsi de sa propre file d’attente, conservée lors des nouveaux rendus ordinaires, et une nouvelle instance est créée lorsque StrictMode répète la mise en place de l’effet après le nettoyage. Le composant enfant utilisant les hooks Uppy n’est monté que lorsqu’une instance est disponible. Ne créez pas de singleton partagé au niveau du module, sauf si toutes les interfaces doivent délibérément partager une seule file d’attente : sinon, des formulaires indépendants verraient et supprimeraient les fichiers des autres formulaires.
La fonction asynchrone assemblyOptions demande une autorisation à un point de terminaison de confiance immédiatement avant le téléversement. Ce point de terminaison doit authentifier et autoriser l’utilisateur courant, appliquer des contrôles contre les abus, choisir un Template soumis à des contraintes et renvoyer une charge utile signée à courte durée de validité. Le navigateur valide la structure de la réponse, mais ne reçoit jamais l’Auth Secret.
yarn add @uppy/core @uppy/dashboard @uppy/react @uppy/transloadit zodimport 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,
})
}Afficher la progression, l’annulation et l’état de l’Assembly à partir d’Uppy
Uppy est un magasin d’état externe. useUppyState abonne React aux valeurs sélectionnées sans maintenir une seconde file d’attente dans l’état du composant, tandis que useUppyEvent expose des événements qui ne sont pas des champs durables du magasin. Le composant lit le nombre de fichiers, la progression globale, l’état du téléversement actif, l’état d’erreur brut et l’événement de création de l’Assembly. Il associe l’erreur à un message stable destiné à l’utilisateur au lieu d’afficher la valeur brute, et il ne recopie pas les fichiers individuels dans une valeur useState distincte.
Dashboard fournit la sélection de fichiers, le glisser-déposer, des aperçus des fichiers locaux pris en charge, un état par fichier et des commandes de téléversement. La région dynamique distincte fournit à l’application environnante une annonce d’état concise, et l’état désactivé natif du bouton indique si l’annulation est disponible. Veillez à localiser les libellés propres à Dashboard lorsque le produit prend en charge plusieurs langues ; le titre, l’état et les erreurs qui l’entourent nécessitent le même traitement.
Détruisez l’instance Uppy lorsque le composant qui la possède est démonté. Cette destruction annule les opérations en cours, supprime les plugins installés et libère les écouteurs d’événements. Un changement de route ne devrait donc pas faire perdre l’unique copie des informations importantes sur la progression : conservez l’identifiant de l’Assembly et tout enregistrement de tâche applicative avant de compter sur des opérations susceptibles de se poursuivre ailleurs.
import type Uppy from '@uppy/core'
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, setUppy] = useState<Uppy | null>(null)
useEffect(() => {
const instance = createImageUploader()
setUppy(instance)
return () => instance.destroy()
}, [])
return uppy == null ? null : <UploadControls uppy={uppy} />
}
interface UploadControlsProps {
uppy: Uppy
}
function UploadControls({ uppy }: UploadControlsProps): ReactNode {
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
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>
)
}Utiliser les aperçus et les restrictions comme fonctionnalités d’interface, et non comme frontières de confiance
Un aperçu local aide une personne à repérer une erreur de sélection avant d’engager le coût du téléversement. Il ne constitue pas le résultat du traitement et ne prouve pas que le fichier est sûr, décodable, correctement orienté ou décrit fidèlement. Limitez les opérations de prévisualisation, car le décodage de nombreuses images volumineuses consomme la mémoire du navigateur. Pour les formats dont le navigateur ne peut pas afficher d’aperçu, présentez le nom du fichier, le type déclaré et la taille sans inventer de miniature.
Les restrictions d’Uppy permettent de rejeter rapidement les erreurs évidentes concernant les types autorisés, la taille individuelle, la taille totale et le nombre de fichiers. Appliquez les mêmes limites au niveau d’un destinataire de confiance ou dans le Template enregistré, car un appelant peut contourner React et modifier les métadonnées des fichiers. Appuyez-vous sur le contenu détecté et, lorsque cela convient, sur une tentative de traitement, puis ne stockez que les résultats acceptés. Laissez allow_steps_override désactivé lorsque le navigateur ne doit pas remplacer le flux de traitement approuvé. Lorsqu’un aperçu ou une restriction entraîne le rejet d’une sélection, affichez un message stable destiné à l’utilisateur et n’exposez pas dans la page les réponses brutes des fournisseurs, les traces de pile, les informations d’identification ni les diagnostics de stockage.
Retour rapide
Expliquez les formats, le nombre et la taille acceptés avant la sélection, puis laissez Uppy signaler les rejets pour non-conformité connue à côté du contrôle.
Politique faisant autorité
Faites respecter les autorisations, les limites en octets, les règles relatives au contenu détecté, les limites de traitement et les destinations d’exportation au-delà du point où le code du navigateur ne peut plus être considéré comme fiable.
Gestion sûre des échecs
Interceptez les échecs d’autorisation et de téléversement à la frontière de confiance, associez-les à un message stable pour l’utilisateur et dirigez les diagnostics bruts uniquement vers les journaux côté serveur.
Concevoir la reprise en fonction de l’interruption à surmonter
Le plugin Transloadit téléverse les fichiers locaux via tus, qui peut reprendre un transfert ayant échoué à partir d’une position en octets confirmée par le serveur, tant que la ressource de téléversement reste valide. retryDelays gère un ensemble limité d’échecs transitoires pendant la durée de vie de l’instance Uppy actuelle. L’annulation est différente : cancelAll() interrompt intentionnellement les opérations en cours, supprime les fichiers et réinitialise l’état du téléversement. L’interface devrait donc indiquer que la sélection sera supprimée.
Le rechargement d’une page détruit l’état de React et d’Uppy conservé en mémoire. La reprise après rechargement nécessite un état persistant côté client et des ressources de téléversement compatibles côté serveur, par exemple dans un flux de traitement avec le plugin Golden Retriever configuré à cet effet. Testez ce comportement avec l’intégration Transloadit réelle avant de le promettre. Les métadonnées locales persistantes peuvent devenir obsolètes, sensibles ou incohérentes avec une autorisation expirée. Définissez donc une durée de conservation et un moyen de supprimer les entrées irrécupérables.
La possibilité de reprise est aussi limitée dans le temps sur le plan opérationnel. Une Assembly ne peut pas accepter des téléversements indéfiniment, et des paramètres signés à courte durée de validité peuvent expirer avant le début d’une nouvelle tentative différée. Distinguez la nouvelle tentative automatique, la mise en pause et la reprise, la restauration après rechargement et le démarrage d’une nouvelle Assembly ; ces opérations répondent à des échecs différents et peuvent réutiliser des identifiants différents.
Confier les fichiers transférés à un flux de traitement multimédia asynchrone
Un Template enregistré devrait décrire le graphe des traitements autorisés : /upload/handle reçoit les fichiers du navigateur, /file/filter peut rejeter les entrées observées qui ne sont pas prises en charge, les Robots de transformation produisent des dérivés dans les limites définies et les Robots de stockage exportent les résultats approuvés lorsque le stockage durable fait partie du flux de traitement. La requête signée sélectionne ce Template ; React ne construit pas de Steps arbitraires et ne contient pas d’informations d’identification permanentes pour le stockage.
Choisissez la valeur de waitForEncoding en fonction du contrat de l’interface. La définir sur false permet au navigateur de terminer après le transfert et convient lorsque l’application enregistre l’identifiant de l’Assembly, affiche un état de traitement distinct et obtient le résultat final à partir d’une Assembly Notification vérifiée ou d’une consultation ultérieure de l’Assembly Status. Attendre l’encodage peut maintenir l’interface en phase avec un traitement court, mais ne remplace pas une réconciliation durable si l’onglet se ferme.
Stockez le contexte applicatif avec l’identifiant de l’Assembly : utilisateur ou tenant authentifié, emplacement prévu pour la ressource, identifiant du Template, date et heure de création et opération applicative à l’origine de l’Assembly. Lorsqu’une notification arrive, vérifiez sa signature, traitez les envois répétés de manière idempotente, confirmez que l’Assembly appartient à l’enregistrement attendu et n’enregistrez que les champs de résultat dont le produit a besoin.
Tester le cycle de vie et le comportement en cas d’échec, pas seulement le scénario nominal
Testez le composant avec un petit fichier autorisé, un fichier trop volumineux, une extension trompeuse, un type non pris en charge, plusieurs fichiers atteignant la limite de nombre, une entrée de zéro octet, une connexion lente, une période hors ligne, un rejet du serveur, l’expiration de l’autorisation, une annulation par l’utilisateur, le démontage du composant et le rechargement de la page. Confirmez quel état est conservé, quelles opérations sont interrompues et quel message reçoit une personne utilisant le clavier ou un lecteur d’écran.
Testez le parcours réel de signature et de traitement en plus du comportement isolé de React. Un objet simulé peut prouver que le bouton se désactive ou qu’un état change, mais seul un jeu de données de test utilisé en intégration prouve que les paramètres signés correspondent, que tus reprend à la position en octets attendue, que le Template rejette le contenu non conforme, que l’identifiant de l’Assembly est enregistré et que la fin du traitement fait l’objet d’une réconciliation une seule fois. Gardez les fichiers de test de petite taille et supprimez les données temporaires de production après l’exécution.
Cycle de vie de React
Effectuez un nouveau rendu sans remplacer l’instance Uppy, puis démontez le composant et vérifiez que les plugins sont supprimés et que les ressources des opérations actives du navigateur sont libérées.
Interaction accessible
Sélectionnez des fichiers sans glisser-déposer, utilisez chaque contrôle au clavier et vérifiez que le rejet, la progression, l’annulation et la fin des opérations sont annoncés sous forme de texte.
Réconciliation du traitement
Fermez la page après la création de l’Assembly, envoyez à nouveau une notification de fin de traitement et prouvez qu’une seule ressource de l’application atteint l’état final correct.
Détails techniques à connaître
- Uppy est un magasin d’état externe. Créez son instance lors de l’initialisation d’un effet et détruisez-la lors du nettoyage de ce même effet pour que l’initialisation supplémentaire de StrictMode reçoive une nouvelle instance. Conservez-la dans l’état pour les rendus ordinaires suivants ; le rendu ne doit pas créer d’instances, de plugins ou d’écouteurs supplémentaires.
- Le hook
useUppyStates’abonne au magasin d’état d’Uppy via le contrat de React pour les magasins externes et sélectionne uniquement l’état dont un composant a besoin. - Le Dashboard React installe son plugin d’interface au montage et le supprime au démontage ; l’application reste responsable de la destruction de l’instance Uppy qu’elle a créée.
- Les restrictions d’Uppy rejettent les sélections non autorisées dans le navigateur, mais les appelants peuvent contourner le code du navigateur et les types MIME déclarés peuvent être erronés. Une validation dans un environnement de confiance reste donc nécessaire.
- Le plugin Transloadit crée une Assembly et téléverse les fichiers locaux vers son point de terminaison tus. Sa fonction de rappel asynchrone
assemblyOptionspeut obtenir des paramètres signés immédiatement avant le début d’un téléversement. - L’option
retryDelaysrelance les téléversements tus après un échec transitoire tant que l’instance Uppy et l’état du téléversement restent disponibles ; elle ne restaure pas à elle seule un transfert après un rechargement ou la fermeture d’un onglet. - L’appel de
cancelAll()émet un événement d’annulation, interrompt les opérations en cours via les modules de téléversement installés, supprime les fichiers actuels et réinitialise l’état de téléversement d’Uppy. - Lorsque
waitForEncodingvaut false, le téléversement Uppy peut se terminer après le transfert des fichiers alors que l’Assembly poursuit le traitement. Enregistrez durablement l’identifiant de l’Assembly et utilisez des notifications vérifiées ou une consultation de l’Assembly Status pour enregistrer durablement la fin du traitement.
Une approche pratique
- 1
Définissez les fichiers acceptés, la destination des octets, le Template de traitement et l’état terminal de l’application avant de créer le composant.
- 2
Créez une seule instance Uppy configurée, affichez Dashboard et un état accessible à partir de son magasin d’état, puis libérez ses ressources au démontage.
- 3
Émettez sur le serveur des options d’Assembly signées assorties de contraintes et appliquez à nouveau les limites des fichiers et les contrôles du contenu observé dans le Template.
- 4
Testez le rejet, l’interruption, l’annulation, les nouvelles tentatives, le démontage, le rechargement, l’expiration de l’autorisation et l’achèvement asynchrone.
Quand Transloadit est utile
Utilisez le Dashboard React et le plugin Transloadit maintenus par Uppy lorsqu’une application React a besoin d’une interface de téléversement soignée, d’un transfert tus avec reprise et de Steps de validation et de transformation gérés côté serveur dans un Template enregistré. Récupérez des options d’Assembly signées à courte durée de validité auprès d’un serveur de confiance et conservez chaque identifiant d’Assembly lorsque le traitement peut se poursuivre après la fermeture de la page.
Périmètre architectural
React gère la durée de vie des composants et affiche l’état du téléversement. Uppy gère la sélection des fichiers dans le navigateur, les aperçus, les restrictions, l’état du transfert et les commandes de nouvelle tentative ou d’annulation. Transloadit autorise et exécute le flux de traitement multimédia enregistré. L’application reste responsable des permissions des utilisateurs, des enregistrements durables des ressources, de la politique de publication et de la réconciliation des états après le démontage du composant.
Questions fréquentes
Faut-il créer Uppy dans un composant React ?
Oui, lorsque ce composant gère la file d’attente. Créez l’instance dans un effet, exposez-la via l’état et détruisez cette même instance lors du nettoyage de l’effet. Les rendus ordinaires la réutilisent ; l’initialisation supplémentaire de StrictMode crée une nouvelle instance après le nettoyage. Utilisez un composant fournisseur partagé uniquement lorsque plusieurs composants utilisent intentionnellement le même outil de téléversement.
Le plugin Transloadit nécessite-t-il un plugin Tus d’Uppy distinct ?
Non, pour les fichiers locaux envoyés à Transloadit. Le plugin Transloadit configure les téléversements tus vers le point de terminaison de l’Assembly. Utilisez le plugin Tus autonome lorsque la destination est un serveur tus distinct plutôt qu’une Assembly Transloadit.
Les restrictions de fichiers d’Uppy sont-elles sûres ?
Non. Elles améliorent le retour dans le navigateur, mais les requêtes peuvent contourner React et les métadonnées des fichiers peuvent être fausses. Répétez les contrôles d’autorisation, les limites en octets, la validation du contenu observé, les contraintes du flux de traitement et la politique de stockage aux frontières de confiance.
Un aperçu d’image Uppy redimensionne-t-il le fichier téléversé ?
Non. Un aperçu relève de l’état de l’interface dans le navigateur. Conservez la source sélectionnée et créez des fichiers dérivés reproductibles dans le flux de traitement, sauf si le produit met délibérément en œuvre une étape de prétraitement distincte côté client.
retryDelays reprendra-t-il un téléversement après un rechargement de la page ?
Non. Les délais entre les nouvelles tentatives couvrent les échecs transitoires tant que l’état courant de l’outil de téléversement reste disponible. La reprise après un rechargement nécessite des métadonnées client conservées durablement et une ressource de téléversement valide sur le serveur ; elle devrait être testée comme une fonctionnalité distincte.
Quand faut-il activer waitForEncoding ?
Activez cette option lorsque l’interface montée doit attendre un traitement court et en afficher directement les résultats. Laissez-la désactivée lorsque le transfert doit se terminer rapidement, puis conservez l’identifiant de l’Assembly et réconciliez l’état du traitement à l’aide de notifications vérifiées ou de consultations de l’état.