Cphml444
Cphml444

Reputation: 89

(Vue) I have problems reusing references from a composable function

I hope it is okay that I included my full code. Otherwise it would be difficult to understand my question.

I have made a composable function for my Vue application, which purpose is to fetch a collection of documents from a database. The composable looks like this:

import { ref, watchEffect } from 'vue'
import { projectFirestore } from '../firebase/config'

const getCollection = (collection, query) => {
    const documents = ref(null)
    const error = ref(null)

    let collectionRef = projectFirestore.collection(collection)
    .orderBy('createdAt')

    if (query) {
        collectionRef = collectionRef.where(...query)
    }

const unsub = collectionRef.onSnapshot(snap => {
        let results = []
        snap.docs.forEach(doc => {
            doc.data().createdAt && results.push({ ...doc.data(), id: doc.id })
        })
        documents.value = results
        error.value = null
    }, (err) => {
        console.log(err.message)
        document.value = null
        error.value = 'could not fetch data'
    })

    watchEffect((onInvalidate) =>{
        onInvalidate(() => unsub());
    });

    return {
        documents,
        error
    }
}

export default getCollection

Then I have a component where I store the data from the database

 <template>
  <div v-for="playlist in playlists" :key="playlist.id">
    <div class="single">
      <div class="thumbnail">
        <img :src="playlist.coverUrl">
      </div>
      <div class="info">
        <h3>{‌{ playlist.title }}</h3>
        <p>created by {‌{ playlist.userName }}</p>
      </div>
      <div class="song-number">
        <p>{‌{ playlist.songs.length }} songs</p>
      </div>
    </div>
  </div>
</template>
 
<script>
export default {
 // receiving props 
  props: ['playlists'],
}
</script>

And finally, I output the data inside the main Home component, where I use the documents and error reference from the composable file.

<template>
  <div class="home">
    <div v-if="error" class="error">Could not fetch the data</div>
    <div v-if="documents">
      <ListView :playlists="documents" />
    </div>
  </div>
</template>
 
<script>
import ListView from '../components/ListView.vue'
import getCollection from '../composables/getCollection'
 
export default {
  name: 'Home',
  components: { ListView },
  setup() {
    const { error, documents } = getCollection('playlists')
 
    return { error, documents }
  }
}
</script>

That is all well and good. But now I wish to add data from a second collection called "books", and the idea is to use the same composable to fetch the data from that collection as well, but the problem is that inside the Home component, I cannot use the references twice. I cannot write:

<template>
      <div class="home">
        <div v-if="error" class="error">Could not fetch the data</div>
        <div v-if="documents">
          <ListView :playlists="documents" />
          <ListView2 :books="documents" />
        </div>
      </div>
    </template>

    export default {
          name: 'Home',
          components: { ListView, ListView2 },
          setup() {
            const { error, documents } = getCollection('playlists')
            const { error, documents } = getCollection('books')
         
            return { error, documents }
          }
        }

This will give me an error because I reference documents and error twice.

So what I tried was to nest these inside the components themselves Example:

<template>
  <div v-for="playlist in playlists" :key="playlist.id">
    <div class="single">
      <div class="thumbnail">
        <img :src="playlist.coverUrl">
      </div>
      <div class="title">
          {{ playlist.title }}
      </div>
      <div class="description">
          {{ playlist.description }}
      </div>
    <div>
      <router-link :to="{ name: 'PlaylistDetails', params: { id: playlist.id }}">Edit</router-link>
    </div>
  </div>
  </div>
</template>
 
<script>
import getCollection from '../composables/getCollection'
export default {
 
  setup() {
      const { documents, error } = getCollection('playlists')
 
      return {
          documents,
          error
      }
  }
}
</script>

This does not work either. I will just get a 404 error if I try to view this component.

So what is the correct way of writing this?

Upvotes: 1

Views: 1035

Answers (1)

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

Try out to rename the destructed fields like :

const { error : playlistsError, documents : playlists } = getCollection('playlists')
const { error : booksError, documents : books } = getCollection('books')
         
return { playlistsError, playlists , booksError , books }

Upvotes: 5

Related Questions