Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
September 10, 2021 02:52 pm GMT

Using Vue Query Hooks For Firebase Database and Image Storage, Mutations and Queries in VueJS

Vue Querypackage provides hooks for fetching, caching and updating asynchronous data in Vue. Based onreact-query. All main concepts are inherited from the main package. Please also check thereact query docs*

I love React Query so I thought it would be great to checkout Vue Query and put together a quick code walkthrough of a simple project. I used Firebase because I already had a project in place, but it could have been any database provider, Supabase might be next !!

Video

High Level Walkthrough of the video including the source code used

Create Vue Project using Vite

npm init vite@latest

install vue-query

npm install vue-query

install vue-router

npm install vue-router@next

install firebase

npm install firebase

Create .env file containing firebase credentials in the root of your project

VITE_APP_PROJECT_ID=image-bahVITE_APP_PROJECT_BUCKET=image-bah.appspot.com

Firebase Functions - we are using the new version of firebase javascript SDK in this example so things look a bit different.

import {  addDoc,  collection,  doc,  getDoc,  getDocs,  getFirestore,  setDoc,} from "firebase/firestore";import { getDownloadURL, getStorage, ref, uploadBytes } from "firebase/storage";

Get All Items

/** * the function called with the vue-query useQuery hook when the page * is rendered */export const getAllImages = async (): Promise<any[]> => {  const results: any[] = [];  const snap = await getDocs(collection(getFirestore(), "ImageInfo"));  snap.forEach((doc) => {    results.push({ id: doc.id, ...doc.data() });  });  return results;};

Get A Single Item

/** * function to query firebase for the specified document */export const getImageDocument = async (docId) => {  const snap = await getDoc(doc(getFirestore(), "ImageInfo", docId));  if (!snap.exists()) throw `Document ${docId} Not Found`;  return { id: snap.id, ...snap.data() };};

Delete A Single Item

/** * function to delete a specified document from firebase   */ export const deleteImageDocument = async (docId: string): Promise<any> => {    const snap = await deleteDoc(doc(getFirestore(), "ImageInfo", docId));    return true  };

Upload Image Information

/** * upload image tp storage and save additional information in * imageData collection */export const uploadImageInfo = async (params: File) => {  console.log(params);  const storageRef = ref(getStorage(), `images/${params.name}`);  // 'file' comes from the Blob or File API  const snapshot = await uploadBytes(storageRef, params, {    contentType: params.type,  });  console.log("Uploaded a blob or file!", snapshot);  const url = await getDownloadURL(storageRef);  await addDoc(collection(getFirestore(), "ImageInfo"), {    imageData: {      size: snapshot.metadata.size,      contentType: snapshot.metadata.contentType,    },    name: snapshot.metadata.name,    url,  });  return { data: snapshot };};

Set up routes and initialize firebase

import { createApp } from "vue";import Home from "./Home.vue";import Detail from "./Detail.vue";import App from "./App.vue";import { createRouter, createWebHistory } from "vue-router";import { initializeApp } from "firebase/app";const routes = [  {    path: "/",    name: "Home",    component: Home,  },  {    path: "/detail/:docId",    name: "Detail",    component: Detail,    props: true,  },];const router = createRouter({  history: createWebHistory(import.meta.env.BASE_URL),  routes: routes as any,});// initialize firebaseconst app = initializeApp({  projectId: import.meta.env.VITE_APP_PROJECT_ID as string,  storageBucket: import.meta.env.VITE_APP_PROJECT_BUCKET as string,});createApp(App).use(router).mount("#app");

Listing All Items In Collection

The home component is just the list component showing the data from the firebase storage collection

<script setup lang="ts">// This starter template is using Vue 3 <script setup> SFCs// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setupimport ImageList from './components/ImageList.vue'</script><template>  <ImageList  /></template>

The ImageList Component, first lets just get a list of date using vue-query, We have imported from firebase-functions the call to query the database getAllImages

<script setup lang="ts">import { useQuery, useQueryClient } from "vue-query";import { getAllImages } from "../firebase-functions";//A QUERY CLIENTconst queryClient = useQueryClient();// A QUERY HOOKconst { isLoading, isError, isFetching, data, error, refetch } = useQuery(  "images",  getAllImages);</script><template>  <div v-if="isLoading">Loading...</div>  <div v-else-if="isError">An error has occurred: {{ error }}</div></template><style scoped>/* style removed for brevity */</style>

Getting A Single Item From the Collection

We have created a detail page to demonstrate how to query just one item from the collection. This script import the firebase function getImageDocument. The document id is passed a parameter and it is used in the useQuery hook to query the database for the document

<script setup lang="ts">import { useQuery } from "vue-query";import { getImageDocument } from "./firebase-functions";//* Define Properties used in Componentconst { docId } = defineProps<{ docId: string }>();// query hook for one item, based on the docIdconst { isLoading, isError, isFetching, data, error, refetch } = useQuery(  ["images", docId],  // call query with parameter  () => getImageDocument(docId as any));</script><template>  <section>    <button @click="$router.replace('/')" style="margin: 16px">GO HOME</button> <div v-if="isLoading">Loading...</div>    <div v-else-if="isError">An error has occurred: {{ error }}</div>    <div v-else-if="data">      <div style="width: 100%">       <img :src="'data.url'"          style="            display: block;            margin-left: auto;            margin-right: auto;            width: 50%;          "        />      </div>      <div style="margin: 16px; overflow-wrap: break-word">        <div>{{ data.name }}</div>        <div>{{ data.imageData.size }}</div>        <div>{{ data.imageData.contentType }}</div>      </div>    </div>  </section></template>

Adding An Item To A Collection, or Mutations

We have added a new section to the template in Home.vue where we have a button that displays the input to select a file and we will upload the file to firebase storage and save some information in a collection.

<section>  <!-- if we get a mutation error, display it -->  <div v-if="mutation.isError.value === true">    An error has occurred: {{ mutation?.error.value }}  </div>  <!-- input element to capture new file -->  <input    id="file-upload"    type="file"    style="display: none"    @change="      (e) => {        e?.target?.files?.length && mutation.mutate(e?.target?.files[0]);      }    "  />  <div>    <button @click="openFileDialog">Upload New Image</button>  </div></section>

In the script section we have added a few new functions and introduced the useMutation hook. The mutation object returned has a mutate function that we call to actually upload the file.

// A MUTATION HOOK, call the mutation function and on success// clear all of the images so that they are reloaded with the new// dataconst mutation = useMutation(uploadImageInfo, {  onSuccess: () => {    queryClient.invalidateQueries("images");  },});/** * opens the file dialog when the button is clicked */const openFileDialog = () => {  document?.getElementById("file-upload")?.click();};

Deleting An Item

in the Detail component we have a button that will trigger another mutation to delete the document using the firebase function we covered earlier. The delete mutation looks like this

// A MUTATION HOOKconst mutation = useMutation(deleteImageDocument, {  onSuccess: () => {    debugger;    queryClient.invalidateQueries("images");    router.replace("/");  },});

we also make changes to the template, one is to catch any mutation errors

<div v-if="mutation.isError.value === true">  An error has occurred: {{ mutation?.error.value }}</div>

the other is the addition of the button to trigger the delete

<div style="display: flex; justify-content: flex-end">  <button @click="mutation.mutate(docId)" style="margin: 16px">    DELETE  </button></div>

Original Link: https://dev.to/aaronksaunders/using-vue-query-hooks-for-firebase-database-and-image-storage-mutations-and-queries-in-vuejs-1nc9

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To