Getting Data From Cloud Firestore Into Your Universal Nuxt App
In the previous article, we created a plugin to integrate our Nuxt app with Firebase. By doing so, we can now easily access Firebase's features anywhere in the app.
In this article, we will retrieve data from Firestore from 2 commonly used methods:
-
Within any Vue instance lifecycle (e.g.
mounted
) -
asyncData
And we'll also be using 2 different styles for each method:
-
Using promises
-
Using
async/await
.
Prerequisites
- Create a Nuxt plugin to integrate our app with Firebase.
Within any Vue instance lifecycle
In our previous article, we injected the Firebase object into the Vue instance. This allows us to access the Firebase object via this
anywhere in the instance's lifecycle, such as in the mounted
method or in any custom methods defined in the methods
property.
Using promises
export default {
data () {
return {
blogs: []
}
},
mounted () {
const db = this.$firebase.firestore()
db.collection('blogs')
.orderBy('created', 'desc')
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
this.blogs.push({
id: doc.id,
...doc.data()
})
})
})
}
}
Using async/await
export default {
data () {
return {
blogs: []
}
},
async mounted () {
const db = this.$firebase.firestore()
const querySnapshot = await db.collection('blogs')
.orderBy('created', 'desc')
.get()
querySnapshot.forEach((doc) => {
this.blogs.push({
id: doc.id,
...doc.data()
})
})
}
}
Using the asyncData method
Since the asyncData
method runs before the Vue instance is initialised, we don't have access to this
yet. However, in our previous article, we also injected the Firebase object into the context
object. This allows us to access the Firebase object via context parameter.
I love using this method because it allows us to retrieve data and process it on the server. That means we can pre-render the content of the page making it immediately available to search engine crawlers.
The value returned by this method will be merged with any data defined in the data
method.
Returning a promise
asyncData ({ app }) {
const teasers = []
const db = app.$firebase.firestore()
return db.collection('teasers')
.where('published', '==', true)
.orderBy('created', 'desc')
.get()
.then((querySnapshot) => {
for (const doc of querySnapshot.docs) {
teasers.push({
id: doc.id,
...doc.data()
})
}
return { teasers }
})
}
Using async/await
async asyncData ({ app }) {
const teasers = []
const db = app.$firebase.firestore()
const querySnapshot = await db.collection('teasers')
.where('published', '==', true)
.orderBy('created', 'desc')
.get()
if (querySnapshot.size > 0) {
for (const doc of querySnapshot.docs) {
teasers.push({
id: doc.id,
...doc.data()
})
}
}
return { teasers }
}
Why pre-render data on the server?
We need to pre-render data on the server whenever we need information to be present immediately inside our initial HTML response. This is useful for making our pages SEO-friendly since we can the content is present in the initial HTML response. In traditional single-page applications, the content of the page usually comes after the initial HTMl is rendered.
Setting header data and important content on the server
<template>
<div>{{ blog.body }}</div>
</template>
<script>
export default {
data () {
return {
blog: null
}
},
head () {
// this.blog is pre-populated in asyncData().
const head = {
title: this.blog.title,
meta: [
{
hid: 'description',
name: 'description',
content: this.blog.description
}
]
}
return head
},
async asyncData ({ app, params, error }) {
const db = app.$firebase.firestore()
try {
const documentSnapshot = await db.collection('blogs').doc(params.id).get()
if (!documentSnapshot.exists) {
error({ statusCode: 404, message: 'Blog not found' })
return
}
// Returned value is merged with the values defined in data().
return {
blog: {
id: documentSnapshot.id,
...documentSnapshot.data()
}
}
} catch (e) {
error({ statusCode: 404, message: 'Blog not found' })
}
}
}
</script>
The code above does the following on the server:
-
Retrieve data using the
asyncData
. -
Use the data in the
<head>
section of the page. -
Use the data in the content.
Conclusion
Using Firestore seemed like a breeze to me. It is a convenient, low-cost, low-maintenance data storage solution. Its documentation is clear and abundant, and its community vibrant.
Being able to access to the Firebase object from anywhere in the code makes coding a lot easier. I also feel that using async/await
made the code cleaner and easier to understand.
Finally, if we need content to be pre-rendered, we can use asyncData
. This is especially useful for making our apps SEO-friendly.