Skip to content

Como Abortar Requisições de API e Lidar com Erros em Vue.js com VueUse

Introdução

Ao trabalhar com operações assíncronas em aplicações Vue, é crucial gerenciar as requisições de forma eficiente, especialmente ao lidar com requisições potencialmente demoradas ou desnecessárias. Neste artigo, exploraremos como abortar requisições usando VueUse e lidar com erros lançados por essas requisições abortadas.

Problema

Em aplicações web modernas, é comum fazer várias chamadas de API para buscar dados. No entanto, existem cenários em que podemos querer cancelar requisições em andamento, como quando um usuário navega para fora de uma página ou quando uma nova requisição substitui uma existente. Além disso, precisamos lidar com erros que podem ocorrer ao abortar essas requisições para garantir uma experiência de usuário tranquila.

Contexto

VueUse fornece um poderoso composable useFetch que nos permite fazer requisições HTTP com funcionalidade de aborto integrada. Vamos ver como podemos aproveitar esse recurso:

typescript
const { abort, canAbort } = useFetch(url);

setTimeout(() => {
  if (canAbort.value) abort();
}, 100);

Neste exemplo, podemos abortar uma requisição usando a função abort fornecida por useFetch. A propriedade canAbort indica se a requisição pode ser abortada.

Também podemos definir um timeout automático para abortar requisições:

typescript
const { data } = useFetch(url, { timeout: 100 });

Isso abortará automaticamente a requisição após 100 milissegundos.

Solução

Agora, vamos implementar uma solução que demonstra como abortar requisições e lidar com erros em um componente Vue. Criaremos um componente que busca mensagens e permite que o usuário cancele a requisição clicando em um botão várias vezes.

vue
<template>
  <div>
    <button @click="getMessages">Buscar Mensagens</button>
    <div v-if="loading">Carregando...</div>

    <ul v-else>
      <li v-for="message in messages" :key="message.id">
        {{ message.text }}
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { useFetch } from '@vueuse/core';
import { defineStore } from 'pinia';

interface Message {
  id: number;
  text: string;
}

const useStore = defineStore('main', {
  state: () => ({
    cancellableRequests: new Map<string, { abort: () => void }>(),
  }),
});

const store = useStore();

const messages = ref<Message[]>([]);
const loading = ref(false);

const getMessages = async (): Message[] => {
  try {
    loading.value = true;

    const url = '/api/messages';
    const token = 'getMessages';

    if (store.cancellableRequests.has(token)) {
      store.cancellableRequests.get(token)?.abort();
      store.cancellableRequests.delete(token);
    }

    const { execute, abort, data, error } = useFetch(url, {
      immediate: false,
    })
      .get()
      .json<{ messages: Message[] }>();

    store.cancellableRequests.set(token, { abort });

    await execute();

    if (error.value) {
      if error.value instanceof Error && error.value.name === 'AbortError') {
        store.cancellableRquests.delete(token);
        return []
      }

      throw new Error('Algo deu errado. Tente novamente mais tarde.')
    }

    return data.value.messages;
  } finally {
    loading.value = false;
  }
};
</script>

Neste exemplo, criamos um componente Vue que demonstra como abortar requisições e lidar com erros:

  1. Definimos uma store Pinia para gerenciar requisições canceláveis.
  2. A função getMessages é responsável por buscar mensagens e lidar com o ciclo de vida da requisição.
  3. Antes de fazer uma nova requisição, verificamos se existe uma requisição existente com o mesmo token e a abortamos se existir.
  4. Usamos useFetch do VueUse para fazer a chamada de API.
  5. Armazenamos a função abort em nossa store Pinia, permitindo cancelar a requisição posteriormente, se necessário.
  6. Lidamos com erros, incluindo o AbortError, que é lançado quando uma requisição é cancelada.
  7. Retornamos as mensagens buscadas se bem-sucedidas, ou um array vazio se a requisição foi abortada.
  8. Por fim, fazemos a limpeza removendo a requisição de nossa store e definindo o estado de carregamento como falso.

Essa implementação permite um gerenciamento eficiente de chamadas de API, evitando requisições de rede desnecessárias e melhorando a experiência geral do usuário.

Conclusão

Ao implementar esta solução, abordamos com sucesso a questão inicial de como abortar requisições usando VueUse e lidar com erros lançados por elas. Essa abordagem permite um gerenciamento eficiente de chamadas de API, evitando requisições de rede desnecessárias e melhorando a experiência geral do usuário.