Obtendo o status de progresso do envio de dados com Axios
Introdução
Vamos mostrar na prática como obter o progresso de cada requisição HTTP sendo feita através do método POST, do front end para o back end utilizando o Axios.
Caso de uso
Imagine que você tem um app front end que faz upload de arquivos para um servidor. Você quer acompanhar e mostrar ao usuário o progresso do envio desses arquivos, como no exemplo abaixo:
Isso é possÃvel e fácil de implementar utilizando o Axios.
Vamos como codar essa funcionalidade.
Mensurando o Progresso de Upload na Prática
Sintaxe básica:
// Utilizando axios
import axios from axios;
// Criando um FormData que armazena a imagem (arquivo)
const data = new FormData();
data.append("file", file, filename);
// Fazendo a requisição para o servidor com método POST
// Enviando o arquivo que está na variável data
// Passando um objeto de configuração que possui um método onUploadProgress
axios
.post("https://my.server.com/posts", data, {
onUploadProgress: (event) => {
let progress: number = Math.round(
(event.loaded * 100) / event.total
);
console.log(
`A imagem ${filename} está ${progress}% carregada... `
);
},
})
.then((response) => {
console.log(
`A imagem ${filename} já foi enviada para o servidor!`
);
})
.catch((err) => {
console.error(
`Houve um problema ao realizar o upload da imagem ${filename} no servidor AWS`
);
console.log(err);
});
Basicamente é realizado uma requisição do tipo POST utilizando o Axios, passando a variável data
, com o arquivo. Passamos também um objeto com a configuração da requisição. Nele contém o método onUploadProgress
que recebe um event
, esse event
contém as propriedades loaded
e total.
loaded é o quanto já foi carregado e total armazena o tamanho total do arquivo.
Então é feito um cálculo de regra de três para definir a percentagem que já foi carregada no servidor. A variável progress
armazena esses valores conforme a função onUploadProgress
é executada automaticamente.
Como estamos lidando com uma Promises, no final da execução o método Then é executado e conseguimos informar que o arquivo já foi enviado.
Se houver algum erro, o método Catch é executado, assim podemos imprimir no log o erro.
Até aqui entendemos a lógica de como funciona o progresso do envio de arquivos.
No código abaixo vamos explorar um pouco mais sobre o assunto, mostrando um trecho de código que foi utilizado no exemplo de caso de uso.
import api from "../services/api";
export interface IFile {
id: string;
name: string;
readableSize: string;
uploaded?: boolean;
preview: string;
file: File | null;
progress?: number;
error?: boolean;
url: string;
}
const [uploadedFiles, setUploadedFiles] = useState<IFile[]>([]);
const updateFile = useCallback((id, data) => {
setUploadedFiles((state) =>
state.map((file) => (file.id === id ? { ...file, ...data } : file))
);
}, []);
const processUpload = useCallback(
(uploadedFile: IFile) => {
const data = new FormData();
if (uploadedFile.file) {
data.append("file", uploadedFile.file, uploadedFile.name);
}
api
.post("posts", data, {
onUploadProgress: (progressEvent) => {
let progress: number = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(
`A imagem ${uploadedFile.name} está ${progress}% carregada... `
);
updateFile(uploadedFile.id, { progress });
},
})
.then((response) => {
console.log(
`A imagem ${uploadedFile.name} já foi enviada para o servidor!`
);
updateFile(uploadedFile.id, {
uploaded: true,
id: response.data._id,
url: response.data.url,
});
})
.catch((err) => {
console.error(
`Houve um problema ao fazer upload da imagem ${uploadedFile.name} no servidor AWS`
);
console.log(err);
updateFile(uploadedFile.id, {
error: true,
});
});
},
[updateFile]
);
Nesse código, o evento de onUploadedFile
é executado seguindo a mesma lógica que explicamos anteriormente, o progresso será calculado e a função updateFile
é chamada a cada update do evento, recebendo o id do arquivo enviado ao servidor e o progresso.
A função updateFile
irá alterar o estado do arquivo em questão, passando o valor atual do progresso que irá refletir na tela com um Loading de progresso usando a lib react-circular-progressbar. Conforme vimos no vÃdeo do caso de uso acima.
Quando é finalizado o upload do arquivo, o método then é executado e invoca a função updateFile
, passando o id fake do arquivo e um objeto que tem o id que o servidor gerou e a URL do arquivo que já foi salva no S3 da AWS.
Na tela vai aparecer um link excluir e um Ãcone representará que o arquivo foi enviado com sucesso!
Algum erro pode acontecer na execução, o servidor não permite arquivos maiores que 2 MB.
Se o usuário enviar um arquivo maior que o limite estabelecido no servidor, o método catch será executado. Então iremos alterar o estado do uploadedFile
com um error: true
que irá alterar o Ãcone no front end, indicando que o arquivo que está no preview não foi enviado por algum motivo — poderÃamos colocar um tooltip para mostrar o log do erro no componente ;)
E temos aqui o resultado esperado:
Conclusão
Objetivo foi mostrar essa funcionalidade bacana do Axios de ouvir o evento de envio de arquivos e mostrar a quantidade em percentual do processamento do envio, com isso podemos mostrar um loading bem legal.
Conseguimos melhorar a experiência do usuário mostrando o progresso do envio arquivo.
O objetivo não foi mostrar o fluxo completo do front end, isso vai ficar para um próximo post. Mas para não te deixar na curiosidade, indiquei um vÃdeo logo abaixo que é para você aprender toda a lógica dessa implementação!
Links
Se você quer aprender a fazer o upload completo de arquivos em Front End e implementar a funcionalidade de progresso de envio de arquivos, acompanhe esse vÃdeo:
Observação: esse vÃdeo é antigo, usando React com classes. Mas vale a pena acompanhar a lógica para implementar esse tipo de funcionalidade, talvez você possa refatorar o projeto para React Hooks ;)
E aÃ, o que achou do post?
Espero que tenha curtido! 💜
O aprendizado é contÃnuo e sempre haverá um próximo nÃvel! 🚀