VueJS – Componente Reutilizável de Carregamento de Dados

É possível contar com os dedos de uma mão as aplicações web ao redor do mundo que não precisam realizar carregamento de dados remotos e exibi-los aos usuários.

Então, assumindo que a sua próxima Single Page Application (construída usando VueJS, logica…


This content originally appeared on DEV Community and was authored by Pablo Veiga

É possível contar com os dedos de uma mão as aplicações web ao redor do mundo que não precisam realizar carregamento de dados remotos e exibi-los aos usuários.

Então, assumindo que a sua próxima Single Page Application (construída usando VueJS, logicamente ?) vai precisar obter dados de um servidor remoto, eu gostaria de te ensinar a construir um componente reutilizável que vai ser responsável por gerenciar a visualização de estado de outros componentes que dependem de carregamento de dados e prover, facilmente, feedback para seus usuários.

Começando pelo começo

Inicialmente, é preciso ter em mente o quão importante é a exibição correta do estado atual da aplicação para que os usuários saibam o que está acontecendo e o que esperar dela.
Isso vai fazer com que eles não fiquem em dúvida se a interface travou enquanto esperam informações serem carregadas e também informá-los caso ocorra algum erro para que possam entrar em contato com o suporte imediatamente, se necessário.

Padrão Loading / Error / Data (Carregamento / Erro / Dado)

Eu não tenho certeza se é um padrão "oficial" (me mande uma mensagem caso você saiba algo a respeito) mas esta é uma forma muito fácil de implementar e que vai ajudar você a organizar a exibição do estado da sua aplicação de forma bastante simples.

Considere o objeto abaixo. Ele representa o estado inicial de uma lista de users (usuários):

const users = {
  loading: false,
  error: null,
  data: []
}

Ao construir objetos neste formato, você poderá alterar o valor de cada atributo de acordo com o que está acontecendo na sua aplicação e utilizá-los para exibir na tela qualquer coisa de acordo com cada estado por vez. Portanto, quando a aplicação estiver carregando os dados, basta setar loading para true e quando o carregamento for concluído, setar para false.

De forma similar, error e data também devem ser atualizados de acordo com o resultado da chamada ao back end: se algum erro ocorreu, você pode atribuir a mensagem ao atributo error e, caso a requisição tenha sido concluída e o dado entregue com sucesso, basta atribuí-lo ao atributo data.

Especializando

Um objeto de estado, como explicado acima, ainda é muito genérico. Vamos inseri-lo no contexto de uma aplicação VueJS.
Faremos isso implementando um componente utilizando slots, o que vai nos permitir passar o dado recebido pelo componente Fetcher para os componentes filho.

De acordo com a documentação do VueJS:

Vue implementa uma API de distribuição de conteúdo que é modelada após o atual detalhamento da especificação dos componentes da Web, usando o elemento <slot> para servir como saída de distribuição de conteúdos.

Para iniciar, crie uma estrutura básica de um componente Vue e implemente o objeto users como variável reativa dentro de data conforme o exemplo abaixo:

export default {
  data() {
    return {
      loading: false,
      error: null,
      data: null
    }
  }
}

Agora, crie o método responsável por fazer o request, carregar os dados e atualizar a variável de estado. Perceba que fazemos a chamada ao método que carrega os dados no hook created para que seja executado assim que o componente for criado.

import { fetchUsers } from '@/services/users'

export default {
  data() {
    return {
      loading: false,
      error: null,
      data: []

    }
  },
  created() {
    this.fetchUsers()
  }
  methods: {
    async fetchUsers() {
      this.loading = true
      this.error = null
      this.users.data = []

      try {
        fetchUsers()
      } catch(error) {
        this.users.error = error
      } finally {
        this.users.loading = false
      }
    }
  }
}

O próximo passo é implementar o template que irá exibir elementos diferentes de acordo com os estados de Loading (carregando), Error (erro) e Data (dados) usando slots para passar o valor de data para componentes filhos, caso esteja definido.

<template>
  <div>
    <div v-if="users.loading">
      Loading...
    </div>
    <div v-else-if="users.error">
      {{ users.error }}
    </div>
    <slot v-else :data="users.data" />    
  </div>
</template>

Com o componente Fetcher construído, vamos utilizá-lo em outro componente chamado UsersList, que irá representar nossa lista de usuários.

<template>
   <UsersFetcher>
     <template #default="{ data }">
       <table>
         <tr>
           <th>ID</th>
           <th>Name</th>
           <th>Age</th>
         </tr>
         <tr v-for="user in data" :key="user.id">
           <td>{{ user.id }}</td>
           <td>{{ user.name }}</td>
           <td>{{ user.age }}</td>
         </tr>
       </table>
     </template>
   </UsersFetcher>
</template>
import UsersFetcher from '@/components/UsersFetcher'

export default {
  name: 'UsersList',
  components: {
    UsersFetcher
  }
}

Tornando o componente reutilizável

Esta foi uma forma muito simples de se implementar o padrão Loading / Error / Data a fim de capturar e exibir feedback correto para os usuários quando a aplicação precisa buscar dados remotos. Porém, a implementação acima não é muito reutilizável já que está carregando e manipulando, estritamente, usuários.

Para tornar o componente mais genérico, basta implementarmos algumas pequenas mudanças e assim será possível utilizá-lo em qualquer lugar onde nossa aplicação precise buscar e exibir dados.

Primeiro, vamos tornar o componente Fetcher mais dinâmico visto que, em uma aplicação real, teremos que carregar diversos tipos de dados que, por sua vez, requerem métodos de serviço e nomes de variáveis específicos.
Vamos utilizar props para passar valores dinâmicos para dentro do componente.

<template>
  <div>
    <div v-if="loading">
      Loading...
    </div>
    <div v-else-if="error">
      {{ error }}
    </div>
    <slot v-else :data="data" />    
  </div>
</template>
export default {
  name: 'Fetcher',
  props: {
    apiMethod: {
      type: Function,
      required: true
    },
    params: {
      type: Object,
      default: () => {}
    },
    updater: {
      type: Function,
      default: (previous, current) => current
    },
    initialValue: {
      type: [Number, String, Array, Object],
      default: null
    }
  }
}

Analisando cada uma das props definidas acima:

apiMethod [obrigatória]: a função responsável por realizar a chamada à API para carregar dados externos

params [opcional]: os parâmetros enviados na chamada do método de serviço (apiMethod), quando necessários. Ex.: quando precisamos carregar dados usando filtros.

updater [opcional]: função que irá transformar os dados recebidos.

initialValue [opcional]: o valor inicial do atributo data do objeto de estado.

Após implementar estas props, vamos criar agora o mecanismo principal que irá permitir que o componente seja reutilizado.
Utilizando as props definidas, podemos agora definir as operações e controlar o estado do componente de acordo com o resultado da requisição.

<template>
  <div>
    <div v-if="loading">
      Loading...
    </div>
    <div v-else-if="error">
      {{ error }}
    </div>
    <slot v-else :data="data" />    
  </div>
</template>
export default {
  name: 'Fetcher',
  props: {
    apiMethod: {
      type: Function,
      required: true
    },
    params: {
      type: Object,
      default: () => {}
    },
    updater: {
      type: Function,
      default: (previous, current) => current
    },
    initialValue: {
      type: [Number, String, Array, Object],
      default: null
    }
  },
  data() {
    return {
      loading: false,
      error: null,
      data: this.initialValue
    }
  },
  methods: {
    fetch() {
      const { method, params } = this
      this.loading = true

      try {
        method(params)
      } catch (error) {
        this.error = error
      } finally {
        this.loading = false
      }
    }
  } 
}

Após implementar estas mudanças, assim ficará o nosso componente Fetcher:

<template>
   <Fetcher :apiMethod="fetchUsers">
     <template #default="{ data }">
       <table>
         <tr>
           <th>ID</th>
           <th>Name</th>
           <th>Age</th>
         </tr>
         <tr v-for="user in data" :key="user.id">
           <td>{{ user.id }}</td>
           <td>{{ user.name }}</td>
           <td>{{ user.age }}</td>
         </tr>
       </table>
     </template>
   </Fetcher>
</template>
import Fetcher from '@/components/Fetcher'
import { fetchUsers } from '@/services/users'

export default {
  name: 'UsersList',
  components: {
    Fetcher
  },
  methods: {
    fetchUsers
  }
}

E é isso! :)
Utilizando apenas conceitos básicos de VueJS como props e slots podemos criar um componente de carregamento de dados reutilizável que será responsável por carregar e exibir os dados e prover feedback apropriado conforme o estado da aplicação.
Além disso, você pode utilizá-lo em qualquer página ou componente que precise carregar dados, independentemente do tipo.

Você encontra um exemplo 100% funcional desta implementação neste repositório.

Espero que tenha gostado. Por favor, comente e compartilhe!

Gostaria de agradecer especialmente a Neil Merton por ter me ajudado a corrigir partes do código utilizado neste artigo.

Imagem de capa por nordwood


This content originally appeared on DEV Community and was authored by Pablo Veiga


Print Share Comment Cite Upload Translate Updates
APA

Pablo Veiga | Sciencx (2021-09-13T21:13:13+00:00) VueJS – Componente Reutilizável de Carregamento de Dados. Retrieved from https://www.scien.cx/2021/09/13/vuejs-componente-reutilizavel-de-carregamento-de-dados/

MLA
" » VueJS – Componente Reutilizável de Carregamento de Dados." Pablo Veiga | Sciencx - Monday September 13, 2021, https://www.scien.cx/2021/09/13/vuejs-componente-reutilizavel-de-carregamento-de-dados/
HARVARD
Pablo Veiga | Sciencx Monday September 13, 2021 » VueJS – Componente Reutilizável de Carregamento de Dados., viewed ,<https://www.scien.cx/2021/09/13/vuejs-componente-reutilizavel-de-carregamento-de-dados/>
VANCOUVER
Pablo Veiga | Sciencx - » VueJS – Componente Reutilizável de Carregamento de Dados. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/09/13/vuejs-componente-reutilizavel-de-carregamento-de-dados/
CHICAGO
" » VueJS – Componente Reutilizável de Carregamento de Dados." Pablo Veiga | Sciencx - Accessed . https://www.scien.cx/2021/09/13/vuejs-componente-reutilizavel-de-carregamento-de-dados/
IEEE
" » VueJS – Componente Reutilizável de Carregamento de Dados." Pablo Veiga | Sciencx [Online]. Available: https://www.scien.cx/2021/09/13/vuejs-componente-reutilizavel-de-carregamento-de-dados/. [Accessed: ]
rf:citation
» VueJS – Componente Reutilizável de Carregamento de Dados | Pablo Veiga | Sciencx | https://www.scien.cx/2021/09/13/vuejs-componente-reutilizavel-de-carregamento-de-dados/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.