Checkpoint: Résolution du problème de latence d'affichage avec double requestAnimationFrame : cette technique garantit que le navigateur peint l'animation à l'écran avant de bloquer sur le fetch. Le premier requestAnimationFrame permet à React de mettre à jour l'état, le second force le navigateur à afficher visuellement l'animation avant de démarrer l'upload. Déployé sur le VPS de production.
This commit is contained in:
@@ -196,53 +196,54 @@ function UploadAttestationDialog({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forcer le rendu synchrone de l'interface AVANT de démarrer l'upload
|
// Afficher immédiatement l'état de chargement
|
||||||
flushSync(() => {
|
setUploading(true);
|
||||||
setUploading(true);
|
setUploadProgress(0);
|
||||||
setUploadProgress(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Démarrer l'upload de manière asynchrone
|
// Utiliser requestAnimationFrame pour garantir que le navigateur
|
||||||
(async () => {
|
// affiche l'animation AVANT de bloquer sur le fetch
|
||||||
try {
|
requestAnimationFrame(() => {
|
||||||
const formData = new FormData();
|
requestAnimationFrame(async () => {
|
||||||
formData.append('file', file);
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
const progressInterval = setInterval(() => {
|
const progressInterval = setInterval(() => {
|
||||||
setUploadProgress(prev => {
|
setUploadProgress(prev => {
|
||||||
if (prev >= 90) return prev;
|
if (prev >= 90) return prev;
|
||||||
return prev + 10;
|
return prev + 10;
|
||||||
});
|
});
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
const response = await fetch('/api/upload-file', {
|
const response = await fetch('/api/upload-file', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
clearInterval(progressInterval);
|
clearInterval(progressInterval);
|
||||||
setUploadProgress(100);
|
setUploadProgress(100);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Erreur lors de l\'upload');
|
throw new Error('Erreur lors de l\'upload');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setFileData({
|
setFileData({
|
||||||
nomFichier: file.name,
|
nomFichier: file.name,
|
||||||
urlFichier: data.url,
|
urlFichier: data.url,
|
||||||
s3Key: data.key,
|
s3Key: data.key,
|
||||||
typeFichier: file.type,
|
typeFichier: file.type,
|
||||||
tailleFichier: file.size,
|
tailleFichier: file.size,
|
||||||
});
|
});
|
||||||
toast.success('Fichier uploadé avec succès');
|
toast.success('Fichier uploadé avec succès');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error('Erreur lors de l\'upload du fichier');
|
toast.error('Erreur lors de l\'upload du fichier');
|
||||||
setUploadProgress(0);
|
setUploadProgress(0);
|
||||||
} finally {
|
} finally {
|
||||||
setUploading(false);
|
setUploading(false);
|
||||||
}
|
}
|
||||||
})(); // Fermer et exécuter la fonction async
|
}); // Fermer requestAnimationFrame interne
|
||||||
|
}); // Fermer requestAnimationFrame externe
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
2
todo.md
2
todo.md
@@ -1476,3 +1476,5 @@
|
|||||||
- [x] Corriger la latence d'affichage du message d'upload (forcer le rendu avant traitement)
|
- [x] Corriger la latence d'affichage du message d'upload (forcer le rendu avant traitement)
|
||||||
|
|
||||||
- [x] Restructurer le flux d'upload avec useEffect pour affichage immédiat
|
- [x] Restructurer le flux d'upload avec useEffect pour affichage immédiat
|
||||||
|
|
||||||
|
- [x] Corriger la latence avec requestAnimationFrame pour affichage avant fetch bloquant
|
||||||
|
|||||||
Reference in New Issue
Block a user