Reputation: 814
I updated Nuxt to the latest version because they introduced the new fetch()
hook.
In my project, I'm retrieving data from Prismic. Before, I was using asyncData()
, but when navigating, it took some time before rendering the pages where asyncData()
was invoked (this is how it works).
The ideal solution is to navigate on that particular page, and show a loading animation while retrieving the data.
The new fetch()
hook seems appropriate because it exposes the $fetchState.pending
in order to check the status of the operation.
Now, the code (I'm retrieving subcategories from the category in a shop):
data(){
return{
docs: []
}
},
async fetch() {
try{
const res = await this.$prismic.api.query(this.$prismic.predicates.at('my.category.uid', this.$route.params.sub))
const el = res.results[0]
const query = await this.$prismic.api.query([this.$prismic.predicates.at('document.type','sub-category'), this.$prismic.predicates.at('my.sub-category.category', el.id)], { orderings: '[my.sub-category.position, my.sub-category.title]' })
this.docs = query.results
}
catch (e) {
console.log(e)
}
}
This works at least client side. Will this work for proper SSR? I mean, in asyncData()
(which is invoked server side), this
is not accessible, nor the data()
. If this is the right solution, what's the deal for using asyncData()
over fetch()
anymore?
Upvotes: 0
Views: 8481
Reputation: 138326
As far as SSR is concerned, fetch
is used the same way asyncData
is used (although there is a difference in page transition timing).
The difference between fetch
and asyncData
:
asyncData
does not have access to this
, while fetch
(in Nuxt >= 2.12) does.asyncData
's return value sets the data of the component, while fetch
's return value does not because fetch
already has access to this
, so it could set data
props directly.fetch
is controlled by two options (fetchOnServer
and fetchDelay
), while asyncData
has no options. When fetchOnServer
(true
by default) is set to false
, the fetch
hook is only called client-side.fetch
is coupled with the $fetchState
object, which provides pending
and timestamp
(related to the current state of the fetch operation); and the error
function (allows you to display an error message). Note that asyncData
is also provided the error
function in its context
argument.fetch
allows for faster page transitions (according to RFC 27).asyncData
is only available to pages, while fetch
can be used by any component (including pages).Aside from the differences above, the semantics of the two methods are identical.
It seems fetch
is unofficially the successor of asyncData
even though both exist simultaneously without a deprecation notice. Since fetch
provides more functionality and addresses the problems of asyncData
, I would reccomend using fetch
exclusively.
Upvotes: 7
Reputation: 814
RESOLVED: Nuxt prompted me with a tiny warning saying that "node-fetch" at least at version 2.6.0 is required. For some reason mine was at 2.1.2.
Upvotes: 2
Reputation: 133
If you are looking for a way to have a loading state for your page components you could use the data with asyncData,
data(){
return{
loading: true
}
},
async asyncData(context) {
try{
const res = await context.app.$prismic.api.query(context.app.$prismic.predicates.at('my.category.uid', context.app.$route.params.sub))
const el = res.results[0]
const query = await context.app.$prismic.api.query([context.app.$prismic.predicates.at('document.type','sub-category'), context.app.$prismic.predicates.at('my.sub-category.category', el.id)], { orderings: '[my.sub-category.position, my.sub-category.title]' })
const docs = query.results
const loading = false
return {docs, el, loading}
}
catch (e) {
console.log(e)
}
}
if you use prismic, (and if you didn't register it as a plugin) you could inject prismic into the context through a plugin
import prismic from 'prismic-javascript'
export default (inject) => {
inject('prismic', prismic)
}
So now you have access to $prismic in the context.
Another approach that I am using when dealing with loading states is using a store module for handling the state of the request.
plugins/loading.js
export default ({store},inject) => {
inject('changeLoading', function(){
store.dispatch('changeLoading')
}
)
}
store/index.js
export const state = () => ({
loading: false
});
export const mutations = {
CHANGE_LOADING(state){
state.loading = !state.loading
}
}
export const actions = {
changeLoading({commit}){
commit('CHANGE_LOADING')
}
}
export const getters = {
getLoading(state){
return state.loading
}
}
so now instead of having a local loading state inside your components you would have a centralized state inside your store that you can change and get.
data(){
return{
loading: this.$store.getters['getLoading']
}
},
async asyncData(context) {
try{
context.app.$changeLoading()
const prismicData = await context.app.$prismic(...)
context.app.$changeLoading()
return {prismicData}
}
catch (e) {
context.app.$changeLoading()
console.log(e)
}
}
Upvotes: 2